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