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.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.configuration.Configuration;
026import org.apache.avalon.framework.configuration.ConfigurationException;
027import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
028import org.apache.avalon.framework.context.Context;
029import org.apache.avalon.framework.context.ContextException;
030import org.apache.avalon.framework.context.Contextualizable;
031import org.apache.avalon.framework.logger.AbstractLogEnabled;
032import org.apache.avalon.framework.service.ServiceException;
033import org.apache.avalon.framework.service.ServiceManager;
034import org.apache.avalon.framework.service.Serviceable;
035import org.apache.cocoon.components.LifecycleHelper;
036
037import org.ametys.plugins.extraction.ExtractionConstants;
038import org.ametys.plugins.extraction.component.CountExtractionComponent;
039import org.ametys.plugins.extraction.component.ExtractionComponent;
040import org.ametys.plugins.extraction.component.MappingQueryExtractionComponent;
041import org.ametys.plugins.extraction.component.QueryExtractionComponent;
042import org.ametys.plugins.extraction.component.ThesaurusExtractionComponent;
043
044/**
045 * This class reads the extraction definition file
046 */
047public class ExtractionDefinitionReader extends AbstractLogEnabled implements Component, Contextualizable, Serviceable
048{
049    /** The component role. */
050    public static final String ROLE = ExtractionDefinitionReader.class.getName();
051    
052    private Context _context;
053    private ServiceManager _serviceManager;
054    
055    public void contextualize(Context context) throws ContextException
056    {
057        _context = context;
058    }
059    
060    public void service(ServiceManager manager) throws ServiceException
061    {
062        _serviceManager = manager;
063    }
064    
065    /**
066     * Read the extraction definition file
067     * @param file extraction definition file
068     * @return the extraction components parsed in the definition file
069     * @throws Exception if an error occurs
070     */
071    public Extraction readExtractionDefinitionFile(File file) throws Exception
072    {
073        long startTime = -1;
074        if (getLogger().isDebugEnabled())
075        {
076            startTime = System.currentTimeMillis();
077            getLogger().debug("Reading definition file");
078        }
079        
080        assert file != null;
081        Configuration configuration = new DefaultConfigurationBuilder().buildFromFile(file);
082        
083        Extraction extraction = new Extraction();
084        
085        _readExtractionDescription(configuration, extraction);
086        _readVariablesDefinition(configuration, extraction);
087        _readExtractionDefinitionFile(configuration, extraction);
088        
089        if (getLogger().isDebugEnabled())
090        {
091            long endTime = System.currentTimeMillis();
092            getLogger().debug("Read definition file in " + (endTime - startTime) + "ms");
093        }
094        
095        return extraction;
096    }
097    
098    /**
099     * Read the extraction definition file
100     * @param file extraction definition file
101     * @return the extraction components parsed in the definition file
102     * @throws Exception if an error occurs
103     */
104    public Extraction readVariablesDefinitionsInExtractionDefinitionFile(File file) throws Exception
105    {
106        assert file != null;
107        
108        Configuration configuration = new DefaultConfigurationBuilder().buildFromFile(file);
109        Extraction extraction = new Extraction();
110        _readVariablesDefinition(configuration, extraction);
111        
112        return extraction;
113    }
114    
115    private void _readExtractionDescription(Configuration configuration, Extraction extraction)
116    {
117        String descriptionId = configuration.getChild(ExtractionConstants.DESCRIPTION_TAG)
118                .getAttribute(ExtractionConstants.DESCRIPTION_IDENTIFIER_ATTRIBUTE_NAME, null);
119        extraction.setDescriptionId(descriptionId);
120    }
121    
122    private void _readVariablesDefinition(Configuration configuration, Extraction extraction) throws ConfigurationException
123    {
124        for (Configuration child : configuration.getChildren())
125        {
126            switch (child.getName())
127            {
128                case ExtractionConstants.OPTIONAL_COLUMNS_TAG:
129                    extraction.setDisplayOptionalColumnsNames(getDisplayOptionalColumnNames(child));
130                    break;
131                case ExtractionConstants.CLAUSES_VARIABLES_TAG:
132                    extraction.setQueryVariablesNamesAndContentTypes(getQueryVariablesNamesAndContentTypes(child));
133                    break;
134                default:
135                    // Do nothing, we only check variables definitions
136            }
137        }
138    }
139    
140    private void _readExtractionDefinitionFile(Configuration configuration, Extraction extraction) throws Exception
141    {
142        for (Configuration child : configuration.getChildren())
143        {
144            switch (child.getName())
145            {
146                case ExtractionConstants.QUERY_COMPONENT_TAG:
147                case ExtractionConstants.THESAURUS_COMPONENT_TAG:
148                case ExtractionConstants.COUNT_COMPONENT_TAG:
149                case ExtractionConstants.MAPPING_QUERY_COMPONENT_TAG:
150                    ExtractionComponent component = _processExtractionComponent(child);
151                    extraction.addExtractionComponent(component);
152                    break;
153                default:
154                    // Do nothing
155            }
156        }
157    }
158
159    private List<String> getDisplayOptionalColumnNames(Configuration configuration) throws ConfigurationException
160    {
161        List<String> names = new ArrayList<>();
162        for (Configuration nameConfiguration : configuration.getChildren("name"))
163        {
164            names.add(nameConfiguration.getValue());
165        }
166        return names;
167    }
168    
169    private Map<String, String> getQueryVariablesNamesAndContentTypes(Configuration configuration)
170    {
171        Map<String, String> variables = new HashMap<>();
172        for (Configuration variable : configuration.getChildren("variable"))
173        {
174            String name = variable.getAttribute("name", null);
175            String contentType = variable.getAttribute("contentType", null);
176            if (null == name || null == contentType)
177            {
178                throw new IllegalArgumentException("Query variables are not well defined. A query variable is defined by a name and a content type.");
179            }
180            variables.put(name, contentType);
181        }
182        return variables;
183    }
184
185    private ExtractionComponent _processExtractionComponent(Configuration componentConfiguration) throws Exception
186    {
187        ExtractionComponent component = null;
188        switch (componentConfiguration.getName())
189        {
190            case "query":
191                component = new QueryExtractionComponent();
192                break;
193            case "count":
194                component = new CountExtractionComponent();
195                break;
196            case "thesaurus":
197                component = new ThesaurusExtractionComponent();
198                break;
199            case "mapping-query":
200                component = new MappingQueryExtractionComponent();
201                break;
202            default:
203                // do nothing
204                break;
205        }
206
207        if (component != null)
208        {
209            LifecycleHelper.setupComponent(component, getLogger(), _context, _serviceManager, componentConfiguration);
210            for (Configuration child : componentConfiguration.getChildren())
211            {
212                ExtractionComponent subComponent = _processExtractionComponent(child);
213                if (null != subComponent)
214                {
215                    component.addSubComponent(subComponent);
216                }
217            }
218        }
219        return component;
220    }
221}