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        _readVariablesDefinition(configuration, extraction);
086        _readExtractionDefinitionFile(configuration, extraction);
087        
088        if (getLogger().isDebugEnabled())
089        {
090            long endTime = System.currentTimeMillis();
091            getLogger().debug("Read definition file in " + (endTime - startTime) + "ms");
092        }
093        
094        return extraction;
095    }
096    
097    /**
098     * Read the extraction definition file
099     * @param file extraction definition file
100     * @return the extraction components parsed in the definition file
101     * @throws Exception if an error occurs
102     */
103    public Extraction readVariablesDefinitionsInExtractionDefinitionFile(File file) throws Exception
104    {
105        assert file != null;
106        
107        Configuration configuration = new DefaultConfigurationBuilder().buildFromFile(file);
108        Extraction extraction = new Extraction();
109        _readVariablesDefinition(configuration, extraction);
110        
111        return extraction;
112    }
113    
114    private void _readVariablesDefinition(Configuration configuration, Extraction extraction) throws ConfigurationException
115    {
116        for (Configuration child : configuration.getChildren())
117        {
118            switch (child.getName())
119            {
120                case ExtractionConstants.OPTIONAL_COLUMNS_TAG:
121                    extraction.setDisplayOptionalColumnsNames(getDisplayOptionalColumnNames(child));
122                    break;
123                case ExtractionConstants.CLAUSES_VARIABLES_TAG:
124                    extraction.setQueryVariablesNamesAndContentTypes(getQueryVariablesNamesAndContentTypes(child));
125                    break;
126                default:
127                    // Do nothing, we only check variables definitions
128            }
129        }
130    }
131    
132    private void _readExtractionDefinitionFile(Configuration configuration, Extraction extraction) throws Exception
133    {
134        for (Configuration child : configuration.getChildren())
135        {
136            switch (child.getName())
137            {
138                case ExtractionConstants.QUERY_COMPONENT_TAG:
139                case ExtractionConstants.THESAURUS_COMPONENT_TAG:
140                case ExtractionConstants.COUNT_COMPONENT_TAG:
141                case ExtractionConstants.MAPPING_QUERY_COMPONENT_TAG:
142                    ExtractionComponent component = _processExtractionComponent(child);
143                    extraction.addExtractionComponent(component);
144                    break;
145                default:
146                    // Do nothing
147            }
148        }
149    }
150
151    private List<String> getDisplayOptionalColumnNames(Configuration configuration) throws ConfigurationException
152    {
153        List<String> names = new ArrayList<>();
154        for (Configuration nameConfiguration : configuration.getChildren("name"))
155        {
156            names.add(nameConfiguration.getValue());
157        }
158        return names;
159    }
160    
161    private Map<String, String> getQueryVariablesNamesAndContentTypes(Configuration configuration)
162    {
163        Map<String, String> variables = new HashMap<>();
164        for (Configuration variable : configuration.getChildren("variable"))
165        {
166            String name = variable.getAttribute("name", null);
167            String contentType = variable.getAttribute("contentType", null);
168            if (null == name || null == contentType)
169            {
170                throw new IllegalArgumentException("Query variables are not well defined. A query variable is defined by a name and a content type.");
171            }
172            variables.put(name, contentType);
173        }
174        return variables;
175    }
176
177    private ExtractionComponent _processExtractionComponent(Configuration componentConfiguration) throws Exception
178    {
179        ExtractionComponent component = null;
180        switch (componentConfiguration.getName())
181        {
182            case "query":
183                component = new QueryExtractionComponent();
184                break;
185            case "count":
186                component = new CountExtractionComponent();
187                break;
188            case "thesaurus":
189                component = new ThesaurusExtractionComponent();
190                break;
191            case "mapping-query":
192                component = new MappingQueryExtractionComponent();
193                break;
194            default:
195                // do nothing
196                break;
197        }
198
199        if (component != null)
200        {
201            LifecycleHelper.setupComponent(component, getLogger(), _context, _serviceManager, componentConfiguration);
202            for (Configuration child : componentConfiguration.getChildren())
203            {
204                ExtractionComponent subComponent = _processExtractionComponent(child);
205                if (null != subComponent)
206                {
207                    component.addSubComponent(subComponent);
208                }
209            }
210        }
211        return component;
212    }
213}