| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.stanbol.enhancer.chain.list.impl; |
| |
| import static org.apache.stanbol.enhancer.servicesapi.helper.ConfigUtils.getState; |
| import static org.apache.stanbol.enhancer.servicesapi.helper.ExecutionPlanHelper.createExecutionPlan; |
| import static org.apache.stanbol.enhancer.servicesapi.helper.ExecutionPlanHelper.writeExecutionNode; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import org.apache.clerezza.rdf.core.Graph; |
| import org.apache.clerezza.rdf.core.MGraph; |
| import org.apache.clerezza.rdf.core.NonLiteral; |
| import org.apache.clerezza.rdf.core.impl.SimpleMGraph; |
| import org.apache.felix.scr.annotations.Component; |
| import org.apache.felix.scr.annotations.ConfigurationPolicy; |
| import org.apache.felix.scr.annotations.Properties; |
| import org.apache.felix.scr.annotations.Property; |
| import org.apache.felix.scr.annotations.Service; |
| import org.apache.stanbol.enhancer.servicesapi.Chain; |
| import org.apache.stanbol.enhancer.servicesapi.ChainException; |
| import org.apache.stanbol.enhancer.servicesapi.helper.ConfigUtils; |
| import org.apache.stanbol.enhancer.servicesapi.impl.AbstractChain; |
| import org.osgi.framework.Constants; |
| import org.osgi.service.cm.ConfigurationException; |
| import org.osgi.service.component.ComponentContext; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * This Chain implementation takes a list of engines names as input |
| * and uses the "org.apache.stanbol.enhancer.engine.order " metadata provided by |
| * such engines to calculate the ExecutionGraph.<p> |
| * |
| * Similar the current WeightedJobManager implementation Engines would be |
| * dependent to each other based on decreasing order values. Engines with the |
| * same order value would could be executed in parallel.<p> |
| * |
| * This implementation is targeted for easy configuration - just a list of the |
| * engine names contained within a chain - but has limited possibilities to |
| * control the execution order within an chain. However it is expected |
| * that it provides enough flexibility for most of the usage scenarios.<p> |
| * |
| * This engine also supports the definition of additional parameters for |
| * Enhancement Engines. The syntax is the same as used by BND tools: |
| * <pre><code> |
| * <engineName>;<param-name>=<param-value> |
| * <engineName>;<param-name> |
| * </code></pre> |
| * Parameter without value are interpreted as enabled boolean switch<p> |
| * |
| * Currently this Chain implementation supports the following Parameter: <ul> |
| * <li> optional: Boolean switch that allows to define that the execution of this |
| * engine is not required. |
| * </ul> |
| * |
| * @author Rupert Westenthaler |
| * |
| */ |
| @Component(inherit=true,configurationFactory=true,metatype=true, |
| policy=ConfigurationPolicy.REQUIRE) |
| @Properties(value={ |
| @Property(name=Chain.PROPERTY_NAME), |
| @Property(name=ListChain.PROPERTY_ENGINE_LIST, cardinality=1000), |
| @Property(name=Constants.SERVICE_RANKING, intValue=0) |
| }) |
| @Service(value=Chain.class) |
| public class ListChain extends AbstractChain implements Chain { |
| |
| private final Logger log = LoggerFactory.getLogger(ListChain.class); |
| |
| /** |
| * The list of Enhancement Engine names used to build the Execution Plan |
| */ |
| public static final String PROPERTY_ENGINE_LIST = "stanbol.enhancer.chain.list.enginelist"; |
| |
| private Set<String> engineNames; |
| |
| private Graph executionPlan; |
| |
| |
| @Override |
| protected void activate(ComponentContext ctx) throws ConfigurationException { |
| super.activate(ctx); |
| Object value = ctx.getProperties().get(PROPERTY_ENGINE_LIST); |
| List<String> configuredChain = new ArrayList<String>(); |
| if(value instanceof String[]){ |
| configuredChain.addAll(Arrays.asList((String[])value)); |
| } else if(value instanceof List<?>){ |
| for(Object o : (List<?>)value){ |
| if(o != null){ |
| configuredChain.add(o.toString()); |
| } |
| } |
| } else { |
| throw new ConfigurationException(PROPERTY_ENGINE_LIST, |
| "The engines of a List Chain MUST BE configured as Array/List of " + |
| "Strings (parsed: "+ |
| (value != null?value.getClass():"null")+")"); |
| } |
| Set<String> engineNames = new HashSet<String>(configuredChain.size()); |
| NonLiteral last = null; |
| MGraph ep = new SimpleMGraph(); |
| NonLiteral epNode = createExecutionPlan(ep, getName()); |
| log.debug("Parse ListChain config:"); |
| for(String line : configuredChain){ |
| try { |
| Entry<String,Map<String,List<String>>> parsed = ConfigUtils.parseConfigEntry(line); |
| if(!engineNames.add(parsed.getKey())){ |
| throw new ConfigurationException(PROPERTY_ENGINE_LIST, |
| "The EnhancementEngine '"+parsed.getKey()+"' is mentioned" |
| + "twice in the configured list!"); |
| } |
| boolean optional = getState(parsed.getValue(), "optional"); |
| log.debug(" > Engine: {} ({})",parsed.getKey(),optional? "optional" : "required"); |
| last = writeExecutionNode(ep, epNode, parsed.getKey(), optional, |
| last == null ? null : Collections.singleton(last)); |
| } catch (IllegalArgumentException e) { |
| throw new ConfigurationException(PROPERTY_ENGINE_LIST, "Unable to parse Chain Configuraiton (message: '"+ |
| e.getMessage()+"')!",e); |
| } |
| } |
| if(engineNames.isEmpty()){ |
| throw new ConfigurationException(PROPERTY_ENGINE_LIST, |
| "The configured chain MUST at least contain a single valid entry!"); |
| } |
| this.engineNames = Collections.unmodifiableSet(engineNames); |
| this.executionPlan = ep.getGraph(); |
| } |
| |
| @Override |
| protected void deactivate(ComponentContext ctx) { |
| this.engineNames = null; |
| this.executionPlan = null; |
| super.deactivate(ctx); |
| } |
| @Override |
| public Graph getExecutionPlan() throws ChainException { |
| return executionPlan; |
| } |
| |
| @Override |
| public Set<String> getEngines() { |
| return engineNames; |
| } |
| |
| } |