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.HashSet;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.configuration.Configuration;
028import org.apache.avalon.framework.configuration.ConfigurationException;
029import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
030import org.apache.avalon.framework.context.Context;
031import org.apache.avalon.framework.context.ContextException;
032import org.apache.avalon.framework.context.Contextualizable;
033import org.apache.avalon.framework.logger.AbstractLogEnabled;
034import org.apache.avalon.framework.service.ServiceException;
035import org.apache.avalon.framework.service.ServiceManager;
036import org.apache.avalon.framework.service.Serviceable;
037import org.apache.cocoon.components.LifecycleHelper;
038
039import org.ametys.core.group.GroupIdentity;
040import org.ametys.core.user.UserIdentity;
041import org.ametys.plugins.core.user.UserHelper;
042import org.ametys.plugins.extraction.ExtractionConstants;
043import org.ametys.plugins.extraction.component.CountExtractionComponent;
044import org.ametys.plugins.extraction.component.ExtractionComponent;
045import org.ametys.plugins.extraction.component.MappingQueryExtractionComponent;
046import org.ametys.plugins.extraction.component.QueryExtractionComponent;
047import org.ametys.plugins.extraction.component.ThesaurusExtractionComponent;
048import org.ametys.plugins.extraction.execution.Extraction.ExtractionProfile;
049import org.ametys.plugins.extraction.execution.Extraction.Visibility;
050
051/**
052 * This class reads the extraction definition file
053 */
054public class ExtractionDefinitionReader extends AbstractLogEnabled implements Component, Contextualizable, Serviceable
055{
056    /** The component role. */
057    public static final String ROLE = ExtractionDefinitionReader.class.getName();
058    
059    private Context _context;
060    private ServiceManager _serviceManager;
061    private UserHelper _userHelper;
062    
063    public void contextualize(Context context) throws ContextException
064    {
065        _context = context;
066    }
067    
068    public void service(ServiceManager manager) throws ServiceException
069    {
070        _serviceManager = manager;
071        _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE);
072    }
073    
074    /**
075     * Read the extraction definition file
076     * @param file extraction definition file
077     * @return the extraction components parsed in the definition file
078     * @throws Exception if an error occurs
079     */
080    public Extraction readExtractionDefinitionFile(File file) throws Exception
081    {
082        long startTime = -1;
083        if (getLogger().isDebugEnabled())
084        {
085            startTime = System.currentTimeMillis();
086            getLogger().debug("Reading definition file");
087        }
088        
089        assert file != null;
090        Configuration configuration = new DefaultConfigurationBuilder().buildFromFile(file);
091        
092        Extraction extraction = new Extraction();
093        
094        _readExtractionDescription(configuration, extraction);
095        _readExtractionRights(configuration, extraction);
096        _readVariablesDefinition(configuration, extraction);
097        _readExtractionDefinitionFile(configuration, extraction);
098        
099        if (getLogger().isDebugEnabled())
100        {
101            long endTime = System.currentTimeMillis();
102            getLogger().debug("Read definition file in " + (endTime - startTime) + "ms");
103        }
104        
105        return extraction;
106    }
107    
108    /**
109     * Read the extraction definition file
110     * @param file extraction definition file
111     * @return the extraction components parsed in the definition file
112     * @throws Exception if an error occurs
113     */
114    public Extraction readVariablesDefinitionsInExtractionDefinitionFile(File file) throws Exception
115    {
116        assert file != null;
117        
118        Configuration configuration = new DefaultConfigurationBuilder().buildFromFile(file);
119        Extraction extraction = new Extraction();
120        _readVariablesDefinition(configuration, extraction);
121        
122        return extraction;
123    }
124    
125    private void _readExtractionDescription(Configuration configuration, Extraction extraction)
126    {
127        String descriptionId = configuration.getChild(ExtractionConstants.DESCRIPTION_TAG)
128                .getAttribute(ExtractionConstants.DESCRIPTION_IDENTIFIER_ATTRIBUTE_NAME, null);
129        extraction.setDescriptionId(descriptionId);
130    }
131    
132    private void _readExtractionRights(Configuration configuration, Extraction extraction) throws ConfigurationException
133    {
134        Configuration visibility = configuration.getChild(ExtractionConstants.VISIBILITY_TAG);
135        extraction.setVisibility(Visibility.valueOf(visibility.getValue(Visibility.PUBLIC.toString()).toUpperCase()));
136        
137        Configuration author = configuration.getChild(ExtractionConstants.AUTHOR_TAG, false);
138        if (author != null)
139        {
140            extraction.setAuthor(_userHelper.xml2userIdentity(author));
141        }
142        
143        Configuration readAccessRight = configuration.getChild(ExtractionConstants.READ_ACCESS_TAG);
144        Set<GroupIdentity> readAccessGroupIdentities = _getGroupsFromConfiguration(readAccessRight);
145        extraction.setGrantedGroups(ExtractionProfile.READ_ACCESS, readAccessGroupIdentities);
146        Set<UserIdentity> readAccessUserIdentities = _getUsersFromConfiguration(readAccessRight);
147        extraction.setGrantedUsers(ExtractionProfile.READ_ACCESS, readAccessUserIdentities);
148        
149        Configuration writeAccessRight = configuration.getChild(ExtractionConstants.WRITE_ACCESS_TAG);
150        Set<GroupIdentity> writeAccessGroupIdentities = _getGroupsFromConfiguration(writeAccessRight);
151        extraction.setGrantedGroups(ExtractionProfile.WRITE_ACCESS, writeAccessGroupIdentities);
152        Set<UserIdentity> writeAccessUserIdentities = _getUsersFromConfiguration(writeAccessRight);
153        extraction.setGrantedUsers(ExtractionProfile.WRITE_ACCESS, writeAccessUserIdentities);
154    }
155
156    private Set<GroupIdentity> _getGroupsFromConfiguration(Configuration right) throws ConfigurationException
157    {
158        Set<GroupIdentity> groupIdentities = new HashSet<>();
159
160        Configuration groups = right.getChild(ExtractionConstants.GROUPS_TAG);
161        for (Configuration group : groups.getChildren(ExtractionConstants.GROUP_TAG))
162        {
163            GroupIdentity groupIdentity = new GroupIdentity(group.getAttribute("id"), group.getAttribute("groupDirectory"));
164            groupIdentities.add(groupIdentity);
165        }
166        
167        return groupIdentities;
168    }
169    
170    private Set<UserIdentity> _getUsersFromConfiguration(Configuration right) throws ConfigurationException
171    {
172        Set<UserIdentity> userIdentities = new HashSet<>();
173
174        Configuration users = right.getChild(ExtractionConstants.USERS_TAG);
175        for (Configuration user : users.getChildren(ExtractionConstants.USER_TAG))
176        {
177            UserIdentity userIdentity = _userHelper.xml2userIdentity(user);
178            userIdentities.add(userIdentity);
179        }
180        
181        return userIdentities;
182    }
183    
184    private void _readVariablesDefinition(Configuration configuration, Extraction extraction) throws ConfigurationException
185    {
186        for (Configuration child : configuration.getChildren())
187        {
188            switch (child.getName())
189            {
190                case ExtractionConstants.OPTIONAL_COLUMNS_TAG:
191                    extraction.setDisplayOptionalColumnsNames(getDisplayOptionalColumnNames(child));
192                    break;
193                case ExtractionConstants.CLAUSES_VARIABLES_TAG:
194                    extraction.setQueryVariablesNamesAndContentTypes(getQueryVariablesNamesAndContentTypes(child));
195                    break;
196                default:
197                    // Do nothing, we only check variables definitions
198            }
199        }
200    }
201    
202    private void _readExtractionDefinitionFile(Configuration configuration, Extraction extraction) throws Exception
203    {
204        for (Configuration child : configuration.getChildren())
205        {
206            switch (child.getName())
207            {
208                case ExtractionConstants.QUERY_COMPONENT_TAG:
209                case ExtractionConstants.THESAURUS_COMPONENT_TAG:
210                case ExtractionConstants.COUNT_COMPONENT_TAG:
211                case ExtractionConstants.MAPPING_QUERY_COMPONENT_TAG:
212                    ExtractionComponent component = _processExtractionComponent(child);
213                    extraction.addExtractionComponent(component);
214                    break;
215                default:
216                    // Do nothing
217            }
218        }
219    }
220
221    private List<String> getDisplayOptionalColumnNames(Configuration configuration) throws ConfigurationException
222    {
223        List<String> names = new ArrayList<>();
224        for (Configuration nameConfiguration : configuration.getChildren("name"))
225        {
226            names.add(nameConfiguration.getValue());
227        }
228        return names;
229    }
230    
231    private Map<String, String> getQueryVariablesNamesAndContentTypes(Configuration configuration)
232    {
233        Map<String, String> variables = new HashMap<>();
234        for (Configuration variable : configuration.getChildren("variable"))
235        {
236            String name = variable.getAttribute("name", null);
237            String contentType = variable.getAttribute("contentType", null);
238            if (null == name || null == contentType)
239            {
240                throw new IllegalArgumentException("Query variables are not well defined. A query variable is defined by a name and a content type.");
241            }
242            variables.put(name, contentType);
243        }
244        return variables;
245    }
246
247    private ExtractionComponent _processExtractionComponent(Configuration componentConfiguration) throws Exception
248    {
249        ExtractionComponent component = null;
250        switch (componentConfiguration.getName())
251        {
252            case "query":
253                component = new QueryExtractionComponent();
254                break;
255            case "count":
256                component = new CountExtractionComponent();
257                break;
258            case "thesaurus":
259                component = new ThesaurusExtractionComponent();
260                break;
261            case "mapping-query":
262                component = new MappingQueryExtractionComponent();
263                break;
264            default:
265                // do nothing
266                break;
267        }
268
269        if (component != null)
270        {
271            LifecycleHelper.setupComponent(component, getLogger(), _context, _serviceManager, componentConfiguration);
272            for (Configuration child : componentConfiguration.getChildren())
273            {
274                ExtractionComponent subComponent = _processExtractionComponent(child);
275                if (null != subComponent)
276                {
277                    component.addSubComponent(subComponent);
278                }
279            }
280        }
281        return component;
282    }
283}