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.io.IOException;
020import java.time.ZonedDateTime;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Locale;
024import java.util.Map;
025
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.cocoon.ProcessingException;
029import org.apache.cocoon.environment.ObjectModelHelper;
030import org.apache.cocoon.environment.Request;
031import org.apache.cocoon.generation.ServiceableGenerator;
032import org.apache.cocoon.xml.AttributesImpl;
033import org.apache.cocoon.xml.XMLUtils;
034import org.apache.commons.lang3.StringUtils;
035import org.apache.excalibur.source.Source;
036import org.apache.excalibur.source.SourceResolver;
037import org.apache.excalibur.source.impl.FileSource;
038import org.xml.sax.SAXException;
039
040import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
041import org.ametys.cms.contenttype.ContentTypesHelper;
042import org.ametys.cms.repository.Content;
043import org.ametys.core.right.RightManager;
044import org.ametys.core.right.RightManager.RightResult;
045import org.ametys.core.user.CurrentUserProvider;
046import org.ametys.plugins.extraction.ExtractionConstants;
047import org.ametys.plugins.extraction.component.ExtractionComponent;
048import org.ametys.plugins.repository.AmetysObjectResolver;
049import org.ametys.runtime.parameter.ParameterHelper;
050
051/**
052 * Extracts query results form a XML definition file
053 */
054public class ExtractionGenerator extends ServiceableGenerator
055{
056    /** The request parameter name for definition file path */
057    static final String FILE_PARAM = "file";
058
059    private RightManager _rightManager;
060    private ExtractionDefinitionReader _reader;
061    private CurrentUserProvider _currentUserProvider;
062    private ContentTypeExtensionPoint _contentTypeExtensionPoint;
063    private AmetysObjectResolver _resolver;
064    private ContentTypesHelper _contentTypesHelper;
065    private SourceResolver _sourceResolver;
066    
067    @Override
068    public void service(ServiceManager serviceManager) throws ServiceException
069    {
070        super.service(serviceManager);
071        _rightManager = (RightManager) manager.lookup(RightManager.ROLE);
072        _reader = (ExtractionDefinitionReader) serviceManager.lookup(ExtractionDefinitionReader.ROLE);
073        _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE);
074        _contentTypeExtensionPoint = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE);
075        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
076        _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE);
077        _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
078    }
079    
080    public void generate() throws IOException, SAXException, ProcessingException
081    {
082        try
083        {
084            if (_rightManager.hasRight(_currentUserProvider.getUser(), "Extraction_Rights_ExecuteExtraction", "/${WorkspaceName}") != RightResult.RIGHT_ALLOW)
085            {
086                String errorMessage = "User " + _currentUserProvider.getUser() + " try to execute extraction with no sufficient rights"; 
087                getLogger().error(errorMessage);
088                throw new IllegalStateException(errorMessage);
089            }
090            
091            Request request = ObjectModelHelper.getRequest(objectModel);
092            String fileName = request.getParameter(FILE_PARAM);
093            String filePath = ExtractionConstants.DEFINITIONS_DIR + fileName;
094            String lang = request.getParameter("lang");
095            
096            Source src = _sourceResolver.resolveURI(filePath);
097            File file = ((FileSource) src).getFile();
098            
099            if (!file.exists())
100            {
101                throw new IllegalArgumentException("The file " + filePath + " does not exist.");
102            }
103            
104            Extraction extraction = _reader.readExtractionDefinitionFile(file);
105            
106            contentHandler.startDocument();
107            
108            AttributesImpl attributes = new AttributesImpl();
109            attributes.addCDATAAttribute("user", _currentUserProvider.getUser().getLogin());
110            attributes.addCDATAAttribute("date", ZonedDateTime.now().format(ParameterHelper.getISODateTimeFormatter()));
111            attributes.addCDATAAttribute("name", file.getName());
112            XMLUtils.startElement(contentHandler, "extraction", attributes);
113
114            ExtractionExecutionContext context = new ExtractionExecutionContext();
115            if (StringUtils.isNotEmpty(lang))
116            {
117                context.setDefaultLocale(new Locale(lang));
118            }
119            context.setDisplayOptionalColumns(_getDisplayOptionalColumns(extraction.getDisplayOptionalColumnsNames(), request));
120            context.setClauseVariables(_getQueryVariables(extraction.getQueryVariablesNamesAndContentTypes(), request));
121            
122            for (ExtractionComponent component : extraction.getExtractionComponents())
123            {
124                component.prepareComponentExecution(context);
125                component.execute(contentHandler, context);
126            }
127
128            XMLUtils.endElement(contentHandler, "extraction");
129            contentHandler.endDocument();
130        }
131        catch (Exception e)
132        {
133            throw new ProcessingException(e);
134        }
135    }
136
137    Map<String, Boolean> _getDisplayOptionalColumns(List<String> displayOptionalColumnsNames, Request request)
138    {
139        Map<String, Boolean> result = new HashMap<>();
140        for (String name : displayOptionalColumnsNames)
141        {
142            String valueAsString = request.getParameter(name);
143            if (null == valueAsString)
144            {
145                throw new IllegalArgumentException("Extraction - There is a variable named '" + name + "' but there is no corresponding value");
146            }
147            result.put(name, Boolean.valueOf(valueAsString));
148        }
149        return result;
150    }
151
152    private Map<String, String> _getQueryVariables(Map<String, String> queryVariablesNamesAndContentTypes, Request request)
153    {
154        Map<String, String> result = new HashMap<>();
155        for (Map.Entry<String, String> entry : queryVariablesNamesAndContentTypes.entrySet())
156        {
157            String name = entry.getKey();
158            String contentTypeId = entry.getValue();
159            if (!_contentTypeExtensionPoint.hasExtension(contentTypeId))
160            {
161                throw new IllegalArgumentException("Extraction - content type '" + contentTypeId + "' used in variable '" + name + "' definition does not exist");
162            }
163            
164            String contentId = request.getParameter(name);
165            if (null == contentId)
166            {
167                throw new IllegalArgumentException("Extraction - There is a variable named '" + name + "' but there is no corresponding value");
168            }
169            
170            Content content = _resolver.resolveById(contentId);
171            if (!_contentTypesHelper.isInstanceOf(content, contentTypeId))
172            {
173                throw new IllegalArgumentException("Extraction - content '" + contentId + "' is not an instance of content type '" + contentTypeId + "', defined by the variable named '" + name + "'");
174            }
175            
176            result.put(name, contentId);
177        }
178        return result;
179    }
180
181}