Modified: stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/EnhancementEngineHelper.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/EnhancementEngineHelper.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/EnhancementEngineHelper.java (original) +++ stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/EnhancementEngineHelper.java Tue May 13 06:26:20 2014 @@ -25,13 +25,16 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.Dictionary; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Random; import java.util.UUID; +import org.apache.clerezza.rdf.core.BNode; import org.apache.clerezza.rdf.core.Language; import org.apache.clerezza.rdf.core.Literal; import org.apache.clerezza.rdf.core.LiteralFactory; @@ -47,7 +50,10 @@ import org.apache.clerezza.rdf.core.impl import org.apache.stanbol.enhancer.servicesapi.Chain; import org.apache.stanbol.enhancer.servicesapi.ContentItem; import org.apache.stanbol.enhancer.servicesapi.EnhancementEngine; +import org.apache.stanbol.enhancer.servicesapi.NoSuchPartException; import org.apache.stanbol.enhancer.servicesapi.ServiceProperties; +import org.apache.stanbol.enhancer.servicesapi.rdf.ExecutionPlan; +import org.apache.stanbol.enhancer.servicesapi.rdf.NamespaceEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -768,4 +774,203 @@ public final class EnhancementEngineHelp ci.getLock().readLock().unlock(); } } + + /* + * Helper Methods for retrieving EnhancementProperties in 0.12 from the + * parsed ContentItem (see STANBOL-1280). + * NOTE: in 1.0.0 those are obsolete as EnhancementProperties will be parsed + * as additional parameter to the computeEnhancement method. + */ + private static final String EHPROP_NS = NamespaceEnum.ehprop.getNamespace(); + private static final int EHPROP_NS_LENGTH = EHPROP_NS.length(); + + /** + * Retrieves the Enhancement Properties for the parsed Engine from the ContentItem. + * <p> + * The returned map will contain: <ol> + * <li> Request scoped properties defined for the parsed enhancement engines + * <li> Request scoped properties defined for chain + * <li> Chain scoped properties defined for the parsed enhancement engine + * <li> Chain scoped properties defined for the chain. + * </ol> + * NOTES: <ul> + * <li> The specification (see <a href="https://issues.apache.org/jira/browse/STANBOL-488">STANBOL-488</a>) + * required properties to start with '<code>enhancer.</code>'. While this + * implementation does not enforce this requirement non compliant properties + * will most likely get filtered earlier and not be part of the returned map. + * <li> Properties of an higher priority do override those with an lower one. + * </ul> + * @param engine the enhancement engine requesting the properties + * @param ci the content item (representing the enhancement request). + * @return The enhancement properties. This is a read/write copy of the + * read-only configuration. + * @see #getEnhancementPropertyDict(EnhancementEngine, ContentItem) + */ + public static Dictionary<String,Object> getEnhancementPropertyDict(EnhancementEngine engine, ContentItem ci){ + return new DictionaryAdapter<String,Object>(getEnhancementProperties(engine, ci)); + } + /** + * Retrieves the Enhancement Properties for the parsed Engine from the ContentItem. + * <p> + * The returned map will contain: <ol> + * <li> Request scoped properties defined for the parsed enhancement engines + * <li> Request scoped properties defined for chain + * <li> Chain scoped properties defined for the parsed enhancement engine + * <li> Chain scoped properties defined for the chain. + * </ol> + * NOTES: <ul> + * <li> The specification (see <a href="https://issues.apache.org/jira/browse/STANBOL-488">STANBOL-488</a>) + * required properties to start with '<code>enhancer.</code>'. While this + * implementation does not enforce this requirement non compliant properties + * will most likely get filtered earlier and not be part of the returned map. + * <li> Properties of an higher priority do override those with an lower one. + * </ul> + * @param engine the enhancement engine requesting the properties + * @param ci the content item (representing the enhancement request). + * @return The enhancement properties. This is a read/write copy of the + * read-only configuration. + * @see #getEnhancementPropertyDict(EnhancementEngine, ContentItem) + */ + public static Map<String,Object> getEnhancementProperties(EnhancementEngine engine, ContentItem ci){ + if(engine == null){ + throw new IllegalArgumentException("The parsed EnhancementEngine MUST NOT be NULL"); + } + if(ci == null){ + throw new IllegalArgumentException("The parsed ContentItem MUST NOT be NULL"); + } + //(1) retrieve Chain scope Enhancement Properties + Map<String,Object> chainExProps = new HashMap<String,Object>(); + Map<String,Object> engineExProps = new HashMap<String,Object>(); + ci.getLock().readLock().lock(); + try{ + MGraph em = ExecutionMetadataHelper.getExecutionMetadata(ci); + //(1.a) retrieve EnhancementProperties from the ep:ExecutionPlan + log.debug("> extract EnhancementProperties form the ExecutionPlan"); + NonLiteral executionPlanNode = ExecutionMetadataHelper.getExecutionPlanNode(em, + ExecutionMetadataHelper.getChainExecution(em, ci.getUri())); + extractEnhancementProperties(chainExProps, em, executionPlanNode, "Chain Execution"); + //(1.b) retrieve Enhancement Properties from the ep:ExectutionNode + // for the parsed EnhancementEngine + log.debug("> extract EnhancementProperties form the ExecutionNode of Engine {}", + engine.getName()); + Iterator<Triple> engineExecutions = em.filter(null, ExecutionPlan.ENGINE, new PlainLiteralImpl(engine.getName())); + //NOTE: we expect only a single execution node for an engine, but if + // there are multiple we will merge the properties of those + while(engineExecutions.hasNext()){ + NonLiteral engineExecution = engineExecutions.next().getSubject(); + if(em.contains(new TripleImpl(executionPlanNode, ExecutionPlan.HAS_EXECUTION_NODE, engineExecution))){ + extractEnhancementProperties(engineExProps,em, engineExecution, "Engine Execution"); + } //else engine execution of a different execution plan + } + } catch(NoSuchPartException e){ //no execution metadata are present + log.debug(" - no ExecutionMetadata are present ..."); + } finally { + ci.getLock().readLock().unlock(); + } + //(2) retrieve Request specific EnhancementProperties + //TODO: in future Stanbol version request specific EnhancementProperties + // will get stored in the ExecutionMetadata. Chain level properties + // with the `em:ChainExecution` node and engine specific properties + // with the `em:EngineExecution` node. + // So this code will need to be refactored similar to the above one + Map<String,Object> epContentPart = ContentItemHelper.getEnhancementPropertiesContentPart(ci); + Map<String,Object> chainProperties = new HashMap<String,Object>(); + Map<String,Object> engineProperties = new HashMap<String,Object>(); + if(epContentPart != null){ + String enginePrefix = new StringBuilder(engine.getName()).append(':').toString(); + log.debug("Retrieve EnhancementProperties for Engine {} and ContentItem {}", + engine.getName(), ci.getUri()); + //Set<String> engineKeys = new HashSet<String>(); + for(Entry<String,Object> entry : epContentPart.entrySet()){ + String key = entry.getKey(); + int sepIndex = key.indexOf(':'); + if(sepIndex < 0){ + log.debug(" ... add chain request level property {}='{}'", key,entry.getValue()); + chainProperties.put(key, entry.getValue()); + } else if(key.startsWith(enginePrefix) && key.length() > enginePrefix.length()){ + key = key.substring(enginePrefix.length(),key.length()); + log.debug(" ... add engine request level property {}='{}'", key,entry.getValue()); + engineProperties.put(key, entry.getValue()); + } // else not a enhancement property for the current engine. + } + } else { + log.debug(" - no Request scope EnhancementProperties for ContentItem",ci.getUri()); + } + //Now we need to merge the properties based on the Enhancement Properties Precedence + //defined by STANBOL-488 + // engineProp > engineEx > chainProp > chainExProp + Map<String,Object> properties = new HashMap<String,Object>(chainExProps); + properties.putAll(engineExProps); + properties.putAll(chainProperties); + properties.putAll(engineProperties); + return properties; + } + + /** + * Extracts all EnhancementProperties from the parsed Node and adds them to + * the parsed map + * @param properties The Map to add the extracted properties. extracted values + * are appended to existing values. + * @param graph the RDF graph containing the data + * @param node the node to extract the properties from + * @param level the name of the level (only used for logging) + */ + private static void extractEnhancementProperties(Map<String,Object> properties, TripleCollection graph, + NonLiteral node, String level) { + log.debug(" - extract {} properties from {}", level, node); + Iterator<Triple> props = graph.filter(node, null, null); + while(props.hasNext()){ + Triple t = props.next(); + String propUri = t.getPredicate().getUnicodeString(); + if(propUri.startsWith(EHPROP_NS)){ + String prop = propUri.substring(EHPROP_NS_LENGTH); + Resource resource = t.getObject(); + Object value = extractEnhancementPropertyValue(resource); + if(value != null && !prop.isEmpty()){ + Object current = properties.get(prop); + if(log.isDebugEnabled()){ + if(current != null){ + log.debug(" ... append {} property '{}' to {}='{}'", + new Object[]{level, value, prop,current}); + } else { + log.debug(" ... add {} property {}='{}'", + new Object[]{level, prop, value}); + } + } + if(current instanceof Collection<?>){ + ((Collection) current).add(value); + } else if(current != null){ + Collection<Object> col = new ArrayList<Object>(4); + col.add(current); + col.add(value); + properties.put(prop, col); + } else { + properties.put(prop, value); + } + } + } + } + } + + /** + * Extracts the EnhancementProperty value from the parsed Resource.<p> + * Currently this will return {@link UriRef#getUnicodeString()} or + * {@link Literal#getLexicalForm()}. For {@link BNode}s <code>null</code> + * is returned. + * @param r the resource to parse the value form + * @return the parsed value + */ + private static Object extractEnhancementPropertyValue(Resource r) { + Object value; + if(r instanceof UriRef){ + value = ((UriRef)r).getUnicodeString(); + } else if(r instanceof Literal){ + value = ((Literal) r).getLexicalForm(); + } else { + value = null; + } + return value; + } + + }
Modified: stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionMetadataHelper.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionMetadataHelper.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionMetadataHelper.java (original) +++ stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionMetadataHelper.java Tue May 13 06:26:20 2014 @@ -243,6 +243,25 @@ public final class ExecutionMetadataHelp return null; } } + /** + * Getter for the execution metadata content part. + * @param contentItem the content item + * @return the content part + * @throws NoSuchPartException if no execution metadata are present in the + * content part + * @since 0.12.1 + */ + public static MGraph getExecutionMetadata(ContentItem contentItem) { + if(contentItem == null) { + throw new IllegalArgumentException("The parsed ContentItme MUST NOT be NULL!"); + } + contentItem.getLock().readLock().lock(); + try{ + return contentItem.getPart(CHAIN_EXECUTION, MGraph.class); + }finally{ + contentItem.getLock().readLock().unlock(); + } + } /** * Getter/Initialiser for the execution metadata content part of the parsed Modified: stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionPlanHelper.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionPlanHelper.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionPlanHelper.java (original) +++ stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/helper/ExecutionPlanHelper.java Tue May 13 06:26:20 2014 @@ -30,6 +30,7 @@ import static org.apache.stanbol.enhance import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.RDF_TYPE; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -42,12 +43,16 @@ import java.util.Set; import org.apache.clerezza.rdf.core.BNode; import org.apache.clerezza.rdf.core.Graph; +import org.apache.clerezza.rdf.core.Literal; import org.apache.clerezza.rdf.core.LiteralFactory; import org.apache.clerezza.rdf.core.MGraph; +import org.apache.clerezza.rdf.core.NoConvertorException; import org.apache.clerezza.rdf.core.NonLiteral; import org.apache.clerezza.rdf.core.Resource; import org.apache.clerezza.rdf.core.Triple; import org.apache.clerezza.rdf.core.TripleCollection; +import org.apache.clerezza.rdf.core.TypedLiteral; +import org.apache.clerezza.rdf.core.UriRef; import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl; import org.apache.clerezza.rdf.core.impl.TripleImpl; import org.apache.stanbol.commons.indexedgraph.IndexedMGraph; @@ -57,6 +62,7 @@ import org.apache.stanbol.enhancer.servi import org.apache.stanbol.enhancer.servicesapi.ServiceProperties; import org.apache.stanbol.enhancer.servicesapi.impl.EnginesTracker; import org.apache.stanbol.enhancer.servicesapi.rdf.ExecutionPlan; +import org.apache.stanbol.enhancer.servicesapi.rdf.NamespaceEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,6 +73,25 @@ public final class ExecutionPlanHelper { private static LiteralFactory lf = LiteralFactory.getInstance(); private ExecutionPlanHelper(){/* Do not allow instances of utility classes*/} + + /** + * Writes all triples for an ep:ExecutionNode to the parsed {@link MGraph}. + * An {@link BNode} is use for representing the execution node resource. + * @param graph the graph to write the triples. MUST NOT be empty + * @param epNode the NonLiteral representing the ep:ExecutionPlan + * @param engineName the name of the engine. MUST NOT be <code>null</code> nor empty + * @param optional if the execution of this node is optional or required + * @param dependsOn other nodes that MUST BE executed before this one. Parse + * <code>null</code> or an empty set if none. + * @return the resource representing the added ep:ExecutionNode. + * @deprecated use {@link #writeExecutionNode(MGraph, NonLiteral, String, boolean, Set, Map)} + * with <code>null</code> as last parameter + */ + @Deprecated + public static NonLiteral writeExecutionNode(MGraph graph,NonLiteral epNode, + String engineName, boolean optional, Set<NonLiteral> dependsOn){ + return writeExecutionNode(graph,epNode,engineName,optional,dependsOn, null); + } /** * Writes all triples for an ep:ExecutionNode to the parsed {@link MGraph}. * An {@link BNode} is use for representing the execution node resource. @@ -76,9 +101,14 @@ public final class ExecutionPlanHelper { * @param optional if the execution of this node is optional or required * @param dependsOn other nodes that MUST BE executed before this one. Parse * <code>null</code> or an empty set if none. + * @param enhProps the EnhancementProperties for this ExecutionNode or + * <code>null</code> if none * @return the resource representing the added ep:ExecutionNode. + * @since 0.12.1 */ - public static NonLiteral writeExecutionNode(MGraph graph,NonLiteral epNode, String engineName, boolean optional, Set<NonLiteral> dependsOn){ + public static NonLiteral writeExecutionNode(MGraph graph,NonLiteral epNode, + String engineName, boolean optional, Set<NonLiteral> dependsOn, + Map<String,Object> enhProps){ if(graph == null){ throw new IllegalArgumentException("The parsed MGraph MUST NOT be NULL!"); } @@ -100,6 +130,7 @@ public final class ExecutionPlanHelper { } } graph.add(new TripleImpl(node, OPTIONAL, lf.createTypedLiteral(optional))); + writeEnhancementProperties(graph, node, engineName, enhProps); return node; } /** @@ -107,8 +138,24 @@ public final class ExecutionPlanHelper { * @param graph the graph * @param chainName the chain name * @return the node representing the ex:ExecutionPlan + * @deprecated use {@link #createExecutionPlan(MGraph, String, Map)} with + * parsing <code>null</code> as last parameter */ + @Deprecated public static NonLiteral createExecutionPlan(MGraph graph,String chainName){ + return createExecutionPlan(graph, chainName, null); + } + + /** + * Creates an ExecutionPlan for the parsed chainName in the parsed Graph + * @param graph the graph + * @param chainName the chain name + * @param enhProps the map with the enhancement properties defined for the + * chain or <code>null</code> if none + * @return the node representing the ex:ExecutionPlan + * @since 0.12.1 + */ + public static NonLiteral createExecutionPlan(MGraph graph,String chainName, Map<String,Object> enhProps){ if(graph == null){ throw new IllegalArgumentException("The parsed MGraph MUST NOT be NULL!"); } @@ -118,6 +165,7 @@ public final class ExecutionPlanHelper { NonLiteral node = new BNode(); graph.add(new TripleImpl(node, RDF_TYPE, EXECUTION_PLAN)); graph.add(new TripleImpl(node, CHAIN,new PlainLiteralImpl(chainName))); + writeEnhancementProperties(graph, node, null, enhProps); return node; } @@ -151,17 +199,49 @@ public final class ExecutionPlanHelper { /** * Creates an execution plan based on the * {@link ServiceProperties#ENHANCEMENT_ENGINE_ORDERING} of the parsed - * EnhancementEngines. NOTE that the parsed list is modified as it is sroted by + * EnhancementEngines. NOTE that the parsed list is modified as it is sorted by * using the {@link EnhancementEngineHelper#EXECUTION_ORDER_COMPARATOR}.<p> * A second parameter with the set of optional engines can be used to define * what {@link ExecutionPlan#EXECUTION_NODE} in the execution plan should be * marked as {@link ExecutionPlan#OPTIONAL}. * @param chainName the name of the Chain to build the execution plan for * @param availableEngines the list of engines - * @param the names of optional engines. + * @param optional the names of optional engines. + * @param missing the names of missing engines * @return the execution plan + * @deprecated use {@link #calculateExecutionPlan(String, List, Set, Set, Map)} + * with <code>null</code> as last argument instead */ - public static Graph calculateExecutionPlan(String chainName, List<EnhancementEngine> availableEngines, Set<String> optional, Set<String> missing) { + @Deprecated + public static Graph calculateExecutionPlan(String chainName, List<EnhancementEngine> availableEngines, + Set<String> optional, Set<String> missing) { + return calculateExecutionPlan(chainName, availableEngines, optional, missing, null); + } + /** + * Creates an execution plan based on the + * {@link ServiceProperties#ENHANCEMENT_ENGINE_ORDERING} of the parsed + * EnhancementEngines. NOTE that the parsed list is modified as it is sorted by + * using the {@link EnhancementEngineHelper#EXECUTION_ORDER_COMPARATOR}.<p> + * A second parameter with the set of optional engines can be used to define + * what {@link ExecutionPlan#EXECUTION_NODE} in the execution plan should be + * marked as {@link ExecutionPlan#OPTIONAL}. + * @param chainName the name of the Chain to build the execution plan for + * @param availableEngines the list of engines + * @param optional the names of optional engines. + * @param missing the names of missing engines + * @param enhProps chain scoped enhancement properties. The key of the outer + * map are the name of the engine or <code>null</code> for the chain. The + * inner map uses the property as key and the value(s) as value. Multiple + * values can be parsed as {@link Collection}. Single values will be + * converted to RDF {@link TypedLiteral}s by using the {@link LiteralFactory}. + * For types not supported by the LiteralFactory the <code>toString()</code> + * method will be used. <code>null</code> can be parsed if no enhancement + * properties are present. + * @return the execution plan + * @since 0.12.1 + */ + public static Graph calculateExecutionPlan(String chainName, List<EnhancementEngine> availableEngines, + Set<String> optional, Set<String> missing, Map<String,Map<String,Object>> enhProps) { if(chainName == null || chainName.isEmpty()){ throw new IllegalArgumentException("The parsed ChainName MUST NOT be empty!"); } @@ -169,13 +249,15 @@ public final class ExecutionPlanHelper { //now we have all required and possible also optional engines // -> build the execution plan MGraph ep = new IndexedMGraph(); - NonLiteral epNode = createExecutionPlan(ep, chainName); + NonLiteral epNode = createExecutionPlan(ep, chainName, + enhProps != null ? enhProps.get(null) : null); Integer prevOrder = null; Set<NonLiteral> prev = null; Set<NonLiteral> current = new HashSet<NonLiteral>(); for(String name : missing){ boolean optionalMissing = optional.contains(name); - NonLiteral node = writeExecutionNode(ep, epNode, name, optionalMissing, null); + NonLiteral node = writeExecutionNode(ep, epNode, name, optionalMissing, null, + enhProps == null ? null : enhProps.get(name)); if(!optionalMissing){ current.add(node); } // else add missing optional engines without any dependsOn restrictions @@ -189,7 +271,10 @@ public final class ExecutionPlanHelper { prevOrder = order; } try { - current.add(writeExecutionNode(ep, epNode, name, optional.contains(name), prev)); + NonLiteral executionNode = writeExecutionNode(ep, epNode, name, + optional.contains(name), prev, + enhProps == null ? null : enhProps.get(name)); + current.add(executionNode); } catch (RuntimeException e){ //add the engine and class to ease debugging in such cases log.error("Exception while writing ExecutionNode for Enhancement Eninge: " @@ -200,6 +285,76 @@ public final class ExecutionPlanHelper { return ep.getGraph(); } /** + * Writes the enhancementProperties for an engine/chain to the parsed + * ExecutionNode + * @param ep The RDF graph holding the execution plan + * @param node the execution node of the engine (or chain) to add the + * enhancement properties + * @param engineName the name of the engine or <code>null</code> in case + * of the chain + * @param enhProps the chain scoped enhancement properties or <code>null</code> + * if none + * @since 0.12.1 + */ + private static void writeEnhancementProperties(MGraph ep, NonLiteral node, String engineName, + Map<String,Object> enhProps) { + if(enhProps == null){ //no enhancement properties for this engine + return; + } + for(Entry<String,Object> enhprop : enhProps.entrySet()){ + if(enhprop.getKey() == null || enhprop.getValue() == null){ + log.warn("Invalid Enhancement Property {} for {} {}", new Object[]{ + enhprop, engineName == null ? "Chain" : "engine", + engineName == null ? "" : engineName}); + } else { + writeEnhancementProperty(ep, node, + new UriRef(NamespaceEnum.ehprop + enhprop.getKey()), + enhprop.getValue()); + } + } + } + + /** + * Writes enhancement property value(s) for the parsed node, property to the + * execution plan graph. + * @param ep the RDF graph holding the execution plan + * @param epNode the execution node + * @param property the property + * @param value the value(s). {@link Collection} and <code>Object[]</code> are + * supported for multiple values. + * @throws NullPointerException if any of the parsed parameter is <code>null</code> + */ + @SuppressWarnings("unchecked") + private static void writeEnhancementProperty(MGraph ep, NonLiteral epNode, + UriRef property, Object value) { + Collection<Object> values; + if(value instanceof Collection<?>){ + values = (Collection<Object>)value; + } else if(value instanceof Object[]){ + values = Arrays.asList((Object[])value); + } else { + values = Collections.singleton(value); + } + for(Object v : values){ + if(v != null){ + Literal literal; + if(v instanceof String){ + literal = new PlainLiteralImpl((String)v); + } else { + try { + literal = lf.createTypedLiteral(v); + } catch (NoConvertorException e){ + log.warn("Use toString() value '{}' for EnhancementProperty " + + "'{}' as no TypedLiteral converter is registered for " + + "class {}", new Object[]{ v, property, v.getClass().getName()}); + literal = new PlainLiteralImpl(v.toString()); + } + } + ep.add(new TripleImpl(epNode, property, literal)); + } + } + } + /** * Utility that checks if the parsed graph contains a valid execution * plan. This method is intended to be used by components that need to * ensure that an parsed graph contains a valid execution plan.<p> Modified: stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/AbstractChain.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/AbstractChain.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/AbstractChain.java (original) +++ stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/AbstractChain.java Tue May 13 06:26:20 2014 @@ -16,11 +16,18 @@ */ package org.apache.stanbol.enhancer.servicesapi.impl; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + import org.apache.felix.scr.annotations.Component; 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.helper.ConfigUtils; import org.osgi.framework.Constants; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.component.ComponentContext; @@ -48,12 +55,22 @@ import org.osgi.service.component.Compon @Service public abstract class AbstractChain implements Chain { + /** + * Property used to configure chain scoped enhancement properties as described + * by <a herf="https://issues.apache.org/jira/browse/STANBOL-488">STANBOL-488</a></p> + * Properties defined by this will get parsed to all enhancement engines in the + * chain. + */ + public static final String PROPERTY_CHAIN_PROPERTIES = "stanbol.enhancer.chain.chainproperties"; + private String name; /** * The {@link ComponentContext} set in the {@link #activate(ComponentContext)} * and reset in the {@link #deactivate(ComponentContext)} method. */ protected ComponentContext context; + + private Map<String,Object> chainProperties; protected void activate(ComponentContext ctx) throws ConfigurationException { this.context = ctx; @@ -71,6 +88,28 @@ public abstract class AbstractChain impl "The name of a Chain MUST be an non empty String " + "(type: "+value.getClass()+" value: "+value+")"); } + value = ctx.getProperties().get(PROPERTY_CHAIN_PROPERTIES); + Collection<String> chainPropsConfig; + if(value instanceof String[]){ + chainPropsConfig = Arrays.asList((String[])value); + } else if(value instanceof Collection<?>){ + chainPropsConfig = new ArrayList<String>(((Collection<?>)value).size()); + for(Object o : (Collection<?>)value){ + if(o != null){ + chainPropsConfig.add(o.toString()); + } + } + } else if(value instanceof String){ + chainPropsConfig = Collections.singleton((String)value); + } else if (value != null){ + throw new ConfigurationException(PROPERTY_CHAIN_PROPERTIES, + "Chain level EnhancementProperties can be parsed as String[]," + + "Collection<String> or String (single value). The actually " + + "parsed type was "+value.getClass().getName()); + } else { + chainPropsConfig = Collections.emptyList(); + } + chainProperties = ConfigUtils.getEnhancementProperties(chainPropsConfig); } protected void deactivate(ComponentContext ctx){ this.context = null; @@ -81,5 +120,9 @@ public abstract class AbstractChain impl public final String getName(){ return name; } + + protected Map<String,Object> getChainProperties(){ + return chainProperties; + } } Modified: stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/SingleEngineChain.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/SingleEngineChain.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/SingleEngineChain.java (original) +++ stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/impl/SingleEngineChain.java Tue May 13 06:26:20 2014 @@ -20,6 +20,7 @@ import static org.apache.stanbol.enhance import static org.apache.stanbol.enhancer.servicesapi.helper.ExecutionPlanHelper.writeExecutionNode; import java.util.Collections; +import java.util.Map; import java.util.Set; import org.apache.clerezza.rdf.core.Graph; @@ -49,15 +50,30 @@ public class SingleEngineChain implement private final EnhancementEngine engine; private final String name; + /** + * Creates a {@link Chain} for a single {@link EnhancementEngine} + * @param engine the engine + */ public SingleEngineChain(EnhancementEngine engine){ + this(engine,null); + } + /** + * Creates a {@link Chain} for a single {@link EnhancementEngine} including + * optional chain scoped enhancement properties + * @param engine the engine + * @param enhProps chain scoped enhancement properties or <code>null</code> + * if none. + * @since 0.12.1 + */ + public SingleEngineChain(EnhancementEngine engine, Map<String,Object> enhProps){ if(engine == null){ throw new IllegalArgumentException("The parsed EnhancementEngine MUST NOT be NULL!"); } this.engine = engine; this.name = engine.getName()+"Chain"; MGraph graph = new IndexedMGraph(); - writeExecutionNode(graph, createExecutionPlan(graph, name), - engine.getName(), false, null); + writeExecutionNode(graph, createExecutionPlan(graph, name, null), + engine.getName(), false, null, enhProps); executionPlan = graph.getGraph(); } Modified: stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/rdf/NamespaceEnum.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/rdf/NamespaceEnum.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/rdf/NamespaceEnum.java (original) +++ stanbol/trunk/enhancer/generic/servicesapi/src/main/java/org/apache/stanbol/enhancer/servicesapi/rdf/NamespaceEnum.java Tue May 13 06:26:20 2014 @@ -97,7 +97,12 @@ public enum NamespaceEnum { * Namespace for Disambiguation related properties and classes (added with * STANBOL-1053) */ - dis("http://stanbol.apache.org/ontology/disambiguation/disambiguation#") + dis("http://stanbol.apache.org/ontology/disambiguation/disambiguation#"), + /** + * Namespace used for EnhancementProperties + * @since 0.12.1 + */ + ehprop("http://stanbol.apache.org/ontology/enhancementproperties#") ; String ns; Modified: stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java (original) +++ stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/reader/ContentItemReader.java Tue May 13 06:26:20 2014 @@ -261,8 +261,9 @@ public class ContentItemReader implement parsedContentIds.add(contentItem.getPartUri(0).getUnicodeString()); } //set the parsed contentIDs to the EnhancementProperties - getEnhancementProperties(contentItem).put(PARSED_CONTENT_URIS, - Collections.unmodifiableSet(parsedContentIds)); + Map<String,Object> ep = getEnhancementProperties(contentItem); + parseEnhancementPropertiesFromParameters(ep); + ep.put(PARSED_CONTENT_URIS, Collections.unmodifiableSet(parsedContentIds)); return contentItem; } /** @@ -308,6 +309,45 @@ public class ContentItemReader implement } return ciUri == null ? null : new UriRef(ciUri); } + + /** + * Parsed EnhancementProperties from the request parameters. <p> + * This does NOT override existing values in the parsed map. + * @param ep the map to add the properties + */ + private void parseEnhancementPropertiesFromParameters(Map<String,Object> ep){ + if(uriInfo == null) { + return; //for unit tests + } + MultivaluedMap<String,String> parameters = uriInfo.getQueryParameters(); + log.debug("read EnhancementPropertis from Request Parameters:"); + for(Entry<String,List<String>> entry : parameters.entrySet()){ + if(entry.getKey().contains("enhancer.")){ + if(!ep.containsKey(entry.getKey())){ + log.debug(" + {}",entry.getKey()); + Object value; + if(entry.getValue() == null || entry.getValue().isEmpty()){ + value = null; + } if(entry.getValue().size() == 1){ + value = entry.getValue().get(0); + } else { + //we do want our own read-only copy! + value = Collections.unmodifiableList( + new ArrayList<String>(entry.getValue())); + } + log.debug(" value: {}", value); + ep.put(entry.getKey(), value); + } else if(log.isDebugEnabled()){ + log.debug(" - ignore key {} because it is already present"); + log.debug(" current value: {}",ep.get(entry.getKey())); + log.debug(" request value: {} (ignored)", entry.getValue()); + } + } else { + log.debug(" - {}", entry.getKey()); + } + } + } + /** * Creates a ContentItem * @param id the ID or <code>null</code> if not known Modified: stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/utils/EnhancementPropertiesHelper.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/utils/EnhancementPropertiesHelper.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/utils/EnhancementPropertiesHelper.java (original) +++ stanbol/trunk/enhancer/jersey/src/main/java/org/apache/stanbol/enhancer/jersey/utils/EnhancementPropertiesHelper.java Tue May 13 06:26:20 2014 @@ -29,6 +29,7 @@ import org.apache.clerezza.rdf.core.Trip import org.apache.clerezza.rdf.core.UriRef; import org.apache.stanbol.enhancer.servicesapi.Blob; import org.apache.stanbol.enhancer.servicesapi.ContentItem; +import org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper; import org.apache.stanbol.enhancer.servicesapi.rdf.ExecutionMetadata; import org.apache.stanbol.enhancer.servicesapi.rdf.ExecutionPlan; @@ -39,14 +40,10 @@ public final class EnhancementProperties private EnhancementPropertiesHelper(){/* no instances allowed*/} /** - * URI used to register an {@link ContentItem#getPart(int, Class) contentPart} - * of the type {@link Map Map<String,Objext>} that contains properties - * for the enhancement process. <p> - * TODO: This might move to servicesapi and also accessible to enhancement - * engines + * @see ContentItemHelper#ENHANCEMENT_PROPERTIES_URI */ - public static final UriRef ENHANCEMENT_PROPERTIES_URI = new UriRef( - "urn:apache.org:stanbol.web:enhancement.properties"); + public static final UriRef ENHANCEMENT_PROPERTIES_URI = + ContentItemHelper.ENHANCEMENT_PROPERTIES_URI; /** * Boolean switch parsed as {@link QueryParam} tha allows to deactivate the * inclusion of the {@link ContentItem#getMetadata()} in the Response @@ -97,26 +94,14 @@ public final class EnhancementProperties public static final String PARSED_CONTENT_URIS = "stanbol.enhancer.web.parsedContentURIs"; /** - * Getter for the EnhancementProperties for an {@link ContentItem}. If they - * do not already exist they are created and added to the ContentItem as - * contentPart with the URI {@link #ENHANCEMENT_PROPERTIES_URI} + * Inits (get or creates) the content part holding the EnhancementProperties * @param ci the contentItem MUST NOT be NULL * @return the enhancement properties * @throws IllegalArgumentException if <code>null</code> is parsed as {@link ContentItem}. + * @see ContentItemHelper#initEnhancementPropertiesContentPart(ContentItem) */ - @SuppressWarnings("unchecked") public static Map<String,Object> getEnhancementProperties(ContentItem ci){ - if(ci == null){ - throw new IllegalArgumentException("The parsed ContentItem MUST NOT be NULL!"); - } - Map<String,Object> enhancementProperties; - try { - enhancementProperties = ci.getPart(ENHANCEMENT_PROPERTIES_URI, Map.class); - } catch (RuntimeException e) { - enhancementProperties = new HashMap<String,Object>(); - ci.addPart(ENHANCEMENT_PROPERTIES_URI, enhancementProperties); - } - return enhancementProperties; + return ContentItemHelper.initEnhancementPropertiesContentPart(ci); } Modified: stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java URL: http://svn.apache.org/viewvc/stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java (original) +++ stanbol/trunk/enhancer/jersey/src/test/java/org/apache/stanbol/enhancer/jersey/ContentItemReaderWriterTest.java Tue May 13 06:26:20 2014 @@ -123,11 +123,7 @@ public class ContentItemReaderWriterTest final Serializer serializer = new Serializer(); serializer.bindSerializingProvider(new JenaSerializerProvider()); serializer.bindSerializingProvider(new JsonLdSerializerProvider()); - ciWriter = new ContentItemWriter() { - protected org.apache.clerezza.rdf.core.serializedform.Serializer getSerializer() { - return serializer; - }; - }; + ciWriter = new ContentItemWriter(serializer); final Parser parser = new Parser(); parser.bindParsingProvider(new JenaParserProvider()); Propchange: stanbol/trunk/integration-tests/ ------------------------------------------------------------------------------ Merged /stanbol/branches/release-0.12/integration-tests:r1594122 Added: stanbol/trunk/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancementPropertiesTest.java URL: http://svn.apache.org/viewvc/stanbol/trunk/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancementPropertiesTest.java?rev=1594140&view=auto ============================================================================== --- stanbol/trunk/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancementPropertiesTest.java (added) +++ stanbol/trunk/integration-tests/src/test/java/org/apache/stanbol/enhancer/it/EnhancementPropertiesTest.java Tue May 13 06:26:20 2014 @@ -0,0 +1,87 @@ +/* + * 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.it; + +import java.nio.charset.Charset; + +import org.junit.Test; + +/** Test that the default chain is called by requesting the "/enhancer" endpoint. */ +public class EnhancementPropertiesTest extends EnhancerTestBase { + + private static final Charset UTF8 = Charset.forName("UTF8"); + + public EnhancementPropertiesTest(){ + super(); + } + protected EnhancementPropertiesTest(String endpoint){ + super(endpoint); + } + protected EnhancementPropertiesTest(String endpoint,String...assertEngines){ + super(endpoint,assertEngines); + } + /** + * This tests if request scoped enhancement properties are correctly processed + * by using the <code>enhancer.engines.dereference.languages</code> amd + * <code>enhancer.engines.dereference.fields</code> supported by the + * Dereference engine (<a href="https://issues.apache.org/jira/browse/STANBOL-1287"> + * STANBOL-1287</a>) + * @throws Exception + */ + @Test + public void testDereferenceEngineProperties() throws Exception { + StringBuilder ehProps = new StringBuilder("?"); + //arabic and russian labels + ehProps.append("enhancer.engines.dereference.languages").append('=').append("ar").append('&'); + ehProps.append("enhancer.engines.dereference.languages").append('=').append("ru").append('&'); + //only rdfs:label and foaf:depiction (also validates ns prefix support) + ehProps.append("enhancer.engines.dereference.fields").append('=').append("rdfs:label").append('&'); + ehProps.append("enhancer.engines.dereference.fields").append('=').append("foaf:depiction"); + executor.execute( + builder.buildPostRequest(getEndpoint()+ehProps.toString()) + .withHeader("Accept","text/rdf+nt") + .withContent("The Stanbol enhancer can detect famous cities such as Paris and people such as Bob Marley.") + ) + .assertStatus(200) + .assertCharset(UTF8.name()) + .assertContentRegexp( + //This expects Paris and Bob marley to be found + "http://fise.iks-project.eu/ontology/entity-reference.*http://dbpedia.org/resource/Paris", + "http://fise.iks-project.eu/ontology/entity-reference.*http://dbpedia.org/resource/Bob_Marley", + //the Arabic and Russian label of paris + "http://www.w3.org/2000/01/rdf-schema#label.*\"Ø¨Ø§Ø±ÙØ³\"@ar", + "http://www.w3.org/2000/01/rdf-schema#label.*\"ÐаÑиж\"@ru", + //the Arabic and Russian label of Bob Marley + "http://www.w3.org/2000/01/rdf-schema#label.*\"Ø¨ÙØ¨ ٠ارÙÙ\"@ar", + "http://www.w3.org/2000/01/rdf-schema#label.*\"ÐаÑли, Ðоб\"@ru", + //foaf:depiction triples for Paris and Bob_Marley + "http://dbpedia.org/resource/Paris.*http://xmlns.com/foaf/0.1/depiction.*http://upload.wikimedia.org/wikipedia/.*", + "http://dbpedia.org/resource/Bob_Marley.*http://xmlns.com/foaf/0.1/depiction.*http://upload.wikimedia.org/wikipedia/.*" + ) + .assertContentRegexp(false, + //we do not expect German nor Italian labels + "http://www.w3.org/2000/01/rdf-schema#label.*\"Paris\"@de", + "http://www.w3.org/2000/01/rdf-schema#label.*\"Bob Marley\"@de", + "http://www.w3.org/2000/01/rdf-schema#label.*\"Parigi\"@it", + "http://www.w3.org/2000/01/rdf-schema#label.*\"Bob Marley\"@it", + //no rdf:type triples for Paris and Bob_Marley + "http://dbpedia.org/resource/Paris.*http://www.w3.org/1999/02/22-rdf-syntax-ns#type", + "http://dbpedia.org/resource/Bob_Marley.*http://www.w3.org/1999/02/22-rdf-syntax-ns#type" + ); + } + +} Modified: stanbol/trunk/parent/pom.xml URL: http://svn.apache.org/viewvc/stanbol/trunk/parent/pom.xml?rev=1594140&r1=1594139&r2=1594140&view=diff ============================================================================== --- stanbol/trunk/parent/pom.xml (original) +++ stanbol/trunk/parent/pom.xml Tue May 13 06:26:20 2014 @@ -720,51 +720,90 @@ <version>${sesame-version}</version> </dependency> <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-trig</artifactId> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-trig</artifactId> + <version>${sesame-version}</version> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-trix</artifactId> + <version>${sesame-version}</version> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-rdfxml</artifactId> + <version>${sesame-version}</version> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-rdfjson</artifactId> + <version>${sesame-version}</version> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-nquads</artifactId> + <version>${sesame-version}</version> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-ntriples</artifactId> + <version>${sesame-version}</version> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-n3</artifactId> <version>${sesame-version}</version> </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-trix</artifactId> - <version>${sesame-version}</version> - </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-rdfxml</artifactId> - <version>${sesame-version}</version> - </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-rdfjson</artifactId> - <version>${sesame-version}</version> - </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-nquads</artifactId> - <version>${sesame-version}</version> - </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-ntriples</artifactId> - <version>${sesame-version}</version> - </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-n3</artifactId> - <version>${sesame-version}</version> - </dependency> - <dependency> - <groupId>org.openrdf.sesame</groupId> - <artifactId>sesame-rio-binary</artifactId> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-binary</artifactId> <version>${sesame-version}</version> - </dependency> + </dependency> <dependency> <groupId>org.openrdf.sesame</groupId> <artifactId>sesame-rio-turtle</artifactId> <version>${sesame-version}</version> </dependency> - + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-repository-contextaware</artifactId> + <version>${sesame-version}</version> + </dependency> + + + <!-- Apache Marmotta --> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-triplestore</artifactId> + <version>${marmotta-version}</version> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>marmotta-util-tripletable</artifactId> + <version>${marmotta-version}</version> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-sparql</artifactId> + <version>${marmotta-version}</version> + </dependency> + <!-- Caching dependencies --> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-caching-infinispan</artifactId> + <version>${marmotta-version}</version> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-caching-ehcache</artifactId> + <version>${marmotta-version}</version> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>kiwi-caching-hazelcast</artifactId> + <version>${marmotta-version}</version> + </dependency> + <!-- Commons --> <dependency> <groupId>commons-io</groupId> @@ -1481,7 +1520,7 @@ <!-- Apache James --> <!-- do we need this? -<dependency> + <dependency> <groupId>org.apache.james</groupId> <artifactId>apache-mime4j</artifactId> <version>0.6</version>
