001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.extraction.execution;
017
018import java.io.File;
019import java.util.ArrayList;
020import java.util.LinkedHashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.excalibur.source.Source;
027import org.apache.excalibur.source.SourceResolver;
028import org.apache.excalibur.source.impl.FileSource;
029
030import org.ametys.core.ui.Callable;
031import org.ametys.core.ui.StaticClientSideElement;
032import org.ametys.plugins.extraction.ExtractionConstants;
033import org.ametys.plugins.extraction.component.ExtractionComponent;
034import org.ametys.plugins.extraction.edition.SaveExtractionHelper;
035import org.ametys.plugins.extraction.execution.Extraction.ClausesVariable;
036import org.ametys.runtime.authentication.AccessDeniedException;
037import org.ametys.runtime.i18n.I18nizableText;
038
039/**
040 *  Tool client side element for extraction edition tool
041 */
042public class ExtractionDetailsToolElement extends StaticClientSideElement
043{
044    private ExtractionDefinitionReader _reader;
045    private SourceResolver _sourceResolver;
046    private SaveExtractionHelper _saveHelper;
047    private ExtractionDAO _extractionDAO;
048    
049    @Override
050    public void service(ServiceManager serviceManager) throws ServiceException
051    {
052        super.service(serviceManager);
053        _reader = (ExtractionDefinitionReader) serviceManager.lookup(ExtractionDefinitionReader.ROLE);
054        _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
055        _saveHelper = (SaveExtractionHelper) serviceManager.lookup(SaveExtractionHelper.ROLE);
056        _extractionDAO = (ExtractionDAO) serviceManager.lookup(ExtractionDAO.ROLE);
057    }
058    
059    /**
060     * Retrieve extraction definition details.
061     * @param relativeDefinitionFilePath The extraction's definition file path, relative to the base definitions directory
062     * @return a <code>Map</code> containing the extraction definition details
063     * @throws Exception if an error occurs
064     */
065    @Callable (rights = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID)
066    public Map<String, Object> getExtractionDefinitionDetails(String relativeDefinitionFilePath) throws Exception
067    {
068        Map<String, Object> extractionDefinitionDetails = new LinkedHashMap<>();
069
070        String absoluteDefinitionFilePath = ExtractionConstants.DEFINITIONS_DIR + relativeDefinitionFilePath;
071        Source src = _sourceResolver.resolveURI(absoluteDefinitionFilePath);
072        File file = ((FileSource) src).getFile();
073        
074        if (!file.exists())
075        {
076            if (getLogger().isWarnEnabled())
077            {
078                getLogger().warn("The file " + relativeDefinitionFilePath + " does not exist.");
079            }
080            
081            extractionDefinitionDetails.put("success", false);
082            extractionDefinitionDetails.put("file-error", "unexisting");
083            return extractionDefinitionDetails;
084        }
085        
086        Extraction extraction = _reader.readExtractionDefinitionFile(file);
087        
088        List<Map<String, Object>> extractionNodes = new ArrayList<>();
089        
090        Map<String, Object> clausesVariablesNode = _getClausesVariablesNode(extraction);
091        extractionNodes.add(clausesVariablesNode);
092        
093        Map<String, Object> optionalColumnsNode = _getOptionalColumnsNode(extraction);
094        extractionNodes.add(optionalColumnsNode);
095        
096        List<Map<String, Object>> componentsNodes = _getComponentNodes(extraction.getExtractionComponents());
097        if (!componentsNodes.isEmpty())
098        {
099            extractionNodes.addAll(componentsNodes);
100        }
101        
102        extractionDefinitionDetails.put("success", true);
103        extractionDefinitionDetails.put("descriptionId", extraction.getDescriptionId());
104        extractionDefinitionDetails.put("children", extractionNodes);
105        return extractionDefinitionDetails;
106    }
107
108    private Map<String, Object> _getClausesVariablesNode(Extraction extraction)
109    {
110        Map<String, Object> clausesVariablesNode = new LinkedHashMap<>();
111        List<ClausesVariable> clausesVariables = extraction.getClausesVariables();
112            
113        List<Map<String, Object>> variables = new ArrayList<>();
114        for (ClausesVariable clausesVariable : clausesVariables)
115        {
116            Map<String, Object> clausesVariableData = new LinkedHashMap<>();
117
118            clausesVariableData.put("name", clausesVariable.name());
119            clausesVariableData.put("type", clausesVariable.type().getStringValue());
120            clausesVariableData.put("contentTypeIds", clausesVariable.contentTypeIds());
121            clausesVariable.searchModelId()
122                           .ifPresent(searchModelId -> clausesVariableData.put("searchModelId", searchModelId));
123            clausesVariable.solrRequest()
124                           .ifPresent(solrRequest -> clausesVariableData.put("solrRequest", solrRequest));
125            
126            variables.add(clausesVariableData);
127        }
128        
129        Map<String, Object> clausesVariablesData = new LinkedHashMap<>();
130        clausesVariablesData.put("variables", variables);
131        
132        clausesVariablesNode.put("text", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_TREE_CLAUSES_VARIABLES_NODE_TEXT"));
133        clausesVariablesNode.put("data", clausesVariablesData);
134        clausesVariablesNode.put("leaf", true);
135        clausesVariablesNode.put("tag", ExtractionConstants.CLAUSES_VARIABLES_TAG);
136        clausesVariablesNode.put("iconCls", "ametysicon-symbol-x");
137        
138        return clausesVariablesNode;
139    }
140
141    private Map<String, Object> _getOptionalColumnsNode(Extraction extraction)
142    {
143        Map<String, Object> optionalColumnsNode = new LinkedHashMap<>();
144        List<String> optionalColumns = extraction.getDisplayOptionalColumnsNames();
145        
146        Map<String, Object> optionalColumnsData = new LinkedHashMap<>();
147        optionalColumnsData.put("names", optionalColumns);
148        
149        optionalColumnsNode.put("text", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_TREE_OPTIONAL_COLUMNS_NODE_TEXT"));
150        optionalColumnsNode.put("data", optionalColumnsData);
151        optionalColumnsNode.put("leaf", true);
152        optionalColumnsNode.put("tag", ExtractionConstants.OPTIONAL_COLUMNS_TAG);
153        optionalColumnsNode.put("iconCls", "ametysicon-table28");
154
155        return optionalColumnsNode;
156    }
157
158    private List<Map<String, Object>> _getComponentNodes(List<ExtractionComponent> components)
159    {
160        List<Map<String, Object>> componentNodes = new ArrayList<>();
161        for (ExtractionComponent component : components)
162        {
163            Map<String, Object> componentNode = component.getComponentDetailsForTree();
164            if (component.getSubComponents().isEmpty())
165            {
166                componentNode.put("leaf", true);
167            }
168            else
169            {
170                
171                componentNode.put("children", _getComponentNodes(component.getSubComponents()));
172            }
173            componentNodes.add(componentNode);
174        }
175        return componentNodes;
176    }
177    
178    /**
179     * Saves modifications on extraction. Creates the definition file if it doesn't exist
180     * @param definitionFileName The extraction definition file name
181     * @param extraction A <code>Map</code> containing definition information
182     * @return <code>true</code> if extraction saving succeed, <code>false</code> otherwise
183     * @throws Exception if an error occurs
184     */
185    @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION)
186    public boolean saveExtraction(String definitionFileName, Map<String, Object> extraction) throws Exception
187    {
188        String definitionFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionFileName;
189        FileSource definitionSrc = (FileSource) _sourceResolver.resolveURI(definitionFilePath);
190        
191        if (!_extractionDAO.canWrite(_currentUserProvider.getUser(), definitionSrc))
192        {
193            throw new AccessDeniedException("User '" + _currentUserProvider.getUser() + "' tried to access extraction feature without convenient right");
194        }
195        
196        return _saveHelper.saveExtraction(definitionFileName, extraction);
197    }
198}