You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by rh...@apache.org on 2013/10/03 17:13:36 UTC

svn commit: r1528907 [2/2] - in /stanbol/branches/disambiguation/enhancement-engines: foaf-disambiguation/ foaf-disambiguation/src/ foaf-disambiguation/src/main/ foaf-disambiguation/src/main/java/ foaf-disambiguation/src/main/java/org/ foaf-disambiguat...

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/CustomDijkstraDistance.java
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/CustomDijkstraDistance.java?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/CustomDijkstraDistance.java (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/CustomDijkstraDistance.java Thu Oct  3 15:13:35 2013
@@ -0,0 +1,524 @@
+package org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph;
+
+/*
+ * Created on Jul 9, 2005
+ *
+ * Copyright (c) 2005, the JUNG Project and the Regents of the University 
+ * of California
+ * All rights reserved.
+ *
+ * This software is open-source under the BSD license; see either
+ * "license.txt" or
+ * http://jung.sourceforge.net/license.txt for a description.
+ */
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections15.FunctorException;
+
+import edu.uci.ics.jung.algorithms.shortestpath.Distance;
+import edu.uci.ics.jung.algorithms.util.BasicMapEntry;
+import edu.uci.ics.jung.algorithms.util.MapBinaryHeap;
+import edu.uci.ics.jung.graph.Graph;
+import edu.uci.ics.jung.graph.Hypergraph;
+
+/**
+ * <p>
+ * Calculates distances in a specified graph, using Dijkstra's single-source-shortest-path algorithm. All edge
+ * weights in the graph must be nonnegative; if any edge with negative weight is found in the course of
+ * calculating distances, an <code>IllegalArgumentException</code> will be thrown. (Note: this exception will
+ * only be thrown when such an edge would be used to update a given tentative distance; the algorithm does not
+ * check for negative-weight edges "up front".)
+ * 
+ * <p>
+ * Distances and partial results are optionally cached (by this instance) for later reference. Thus, if the 10
+ * closest vertices to a specified source vertex are known, calculating the 20 closest vertices does not
+ * require starting Dijkstra's algorithm over from scratch.
+ * </p>
+ * 
+ * <p>
+ * Distances are stored as double-precision values. If a vertex is not reachable from the specified source
+ * vertex, no distance is stored. <b>This is new behavior with version 1.4</b>; the previous behavior was to
+ * store a value of <code>Double.POSITIVE_INFINITY</code>. This change gives the algorithm an approximate
+ * complexity of O(kD log k), where k is either the number of requested targets or the number of reachable
+ * vertices (whichever is smaller), and D is the average degree of a vertex.
+ * </p>
+ * 
+ * <p>
+ * The elements in the maps returned by <code>getDistanceMap</code> are ordered (that is, returned by the
+ * iterator) by nondecreasing distance from <code>source</code>.
+ * </p>
+ * 
+ * <p>
+ * Users are cautioned that distances calculated should be assumed to be invalidated by changes to the graph,
+ * and should invoke <code>reset()</code> when appropriate so that the distances can be recalculated.
+ * </p>
+ * 
+ * @author Joshua O'Madadhain
+ * @author Tom Nelson converted to jung2
+ */
+public class CustomDijkstraDistance<V,E> implements Distance<V> {
+    protected Hypergraph<V,E> g;
+    protected Transformer<E,? extends Number> nev;
+    protected Map<V,SourceData> sourceMap; // a map of source vertices to an instance of SourceData
+    protected boolean cached;
+    protected double max_distance;
+    protected int max_targets;
+
+    /**
+     * <p>
+     * Creates an instance of <code>DijkstraShortestPath</code> for the specified graph and the specified
+     * method of extracting weights from edges, which caches results locally if and only if
+     * <code>cached</code> is <code>true</code>.
+     * 
+     * @param g
+     *            the graph on which distances will be calculated
+     * @param nev
+     *            the class responsible for returning weights for edges
+     * @param cached
+     *            specifies whether the results are to be cached
+     * @return
+     */
+    public CustomDijkstraDistance(Hypergraph<V,E> g, Transformer<E,? extends Number> nev, boolean cached) {
+        this.g = g;
+        this.nev = nev;
+        this.sourceMap = new HashMap<V,SourceData>();
+        this.cached = cached;
+        this.max_distance = Double.POSITIVE_INFINITY;
+        this.max_targets = Integer.MAX_VALUE;
+    }
+
+    /**
+     * <p>
+     * Creates an instance of <code>DijkstraShortestPath</code> for the specified graph and the specified
+     * method of extracting weights from edges, which caches results locally.
+     * 
+     * @param g
+     *            the graph on which distances will be calculated
+     * @param nev
+     *            the class responsible for returning weights for edges
+     */
+    public CustomDijkstraDistance(Hypergraph<V,E> g, Transformer<E,? extends Number> nev) {
+        this(g, nev, true);
+    }
+
+    /**
+     * <p>
+     * Creates an instance of <code>DijkstraShortestPath</code> for the specified unweighted graph (that is,
+     * all weights 1) which caches results locally.
+     * 
+     * @param g
+     *            the graph on which distances will be calculated
+     */
+    @SuppressWarnings("unchecked")
+    public CustomDijkstraDistance(Graph<V,E> g) {
+        this(g, new ConstantTransformer(1), true);
+    }
+
+    /**
+     * <p>
+     * Creates an instance of <code>DijkstraShortestPath</code> for the specified unweighted graph (that is,
+     * all weights 1) which caches results locally.
+     * 
+     * @param g
+     *            the graph on which distances will be calculated
+     * @param cached
+     *            specifies whether the results are to be cached
+     */
+    @SuppressWarnings("unchecked")
+    public CustomDijkstraDistance(Graph<V,E> g, boolean cached) {
+        this(g, new ConstantTransformer(1), cached);
+    }
+
+    /**
+     * Implements Dijkstra's single-source shortest-path algorithm for weighted graphs. Uses a
+     * <code>MapBinaryHeap</code> as the priority queue, which gives this algorithm a time complexity of O(m
+     * lg n) (m = # of edges, n = # of vertices). This algorithm will terminate when any of the following have
+     * occurred (in order of priority):
+     * <ul>
+     * <li>the distance to the specified target (if any) has been found
+     * <li>no more vertices are reachable
+     * <li>the specified # of distances have been found, or the maximum distance desired has been exceeded
+     * <li>all distances have been found
+     * </ul>
+     * 
+     * @param source
+     *            the vertex from which distances are to be measured
+     * @param numDests
+     *            the number of distances to measure
+     * @param targets
+     *            the set of vertices to which distances are to be measured
+     */
+    protected LinkedHashMap<V,Number> singleSourceShortestPath(V source, Collection<V> targets, int numDests) {
+        SourceData sd = getSourceData(source);
+
+        Set<V> to_get = new HashSet<V>();
+        if (targets != null) {
+            to_get.addAll(targets);
+            Set<V> existing_dists = sd.distances.keySet();
+            for (V o : targets) {
+                if (existing_dists.contains(o)) to_get.remove(o);
+            }
+        }
+
+        // if we've exceeded the max distance or max # of distances we're willing to calculate, or
+        // if we already have all the distances we need,
+        // terminate
+        if (sd.reached_max || (targets != null && to_get.isEmpty()) || (sd.distances.size() >= numDests)) {
+            return sd.distances;
+        }
+
+        while (!sd.unknownVertices.isEmpty() && (sd.distances.size() < numDests || !to_get.isEmpty())) {
+            Map.Entry<V,Number> p = sd.getNextVertex();
+            V v = p.getKey();
+            double v_dist = p.getValue().doubleValue();
+            to_get.remove(v);
+            if (v_dist > this.max_distance) {
+                // we're done; put this vertex back in so that we're not including
+                // a distance beyond what we specified
+                sd.restoreVertex(v, v_dist);
+                sd.reached_max = true;
+                break;
+            }
+            sd.dist_reached = v_dist;
+
+            if (sd.distances.size() >= this.max_targets) {
+                sd.reached_max = true;
+                break;
+            }
+
+            for (E e : getEdgesToCheck(v)) {
+                for (V w : g.getIncidentVertices(e)) {
+                    if (!sd.distances.containsKey(w)) {
+                        double edge_weight = nev.transform(e).doubleValue();
+                        if (edge_weight < 0) throw new IllegalArgumentException(
+                                "Edges weights must be non-negative");
+                        double new_dist = v_dist + edge_weight;
+                        if (!sd.estimatedDistances.containsKey(w)) {
+                            sd.createRecord(w, e, new_dist);
+                        } else {
+                            double w_dist = ((Double) sd.estimatedDistances.get(w)).doubleValue();
+                            if (new_dist < w_dist) // update tentative distance & path for w
+                            sd.update(w, e, new_dist);
+                        }
+                    }
+                }
+            }
+        }
+        return sd.distances;
+    }
+
+    protected SourceData getSourceData(V source) {
+        SourceData sd = sourceMap.get(source);
+        if (sd == null) sd = new SourceData(source);
+        return sd;
+    }
+
+    /**
+     * Returns the set of edges incident to <code>v</code> that should be tested. By default, this is the set
+     * of outgoing edges for instances of <code>Graph</code>, the set of incident edges for instances of
+     * <code>Hypergraph</code>, and is otherwise undefined.
+     */
+    protected Collection<E> getEdgesToCheck(V v) {
+        if (g instanceof Graph) return ((Graph<V,E>) g).getOutEdges(v);
+        else return g.getIncidentEdges(v);
+
+    }
+
+    /**
+     * Returns the length of a shortest path from the source to the target vertex, or null if the target is
+     * not reachable from the source. If either vertex is not in the graph for which this instance was
+     * created, throws <code>IllegalArgumentException</code>.
+     * 
+     * @see #getDistanceMap(Object)
+     * @see #getDistanceMap(Object,int)
+     */
+    public Number getDistance(V source, V target) {
+        if (g.containsVertex(target) == false) throw new IllegalArgumentException("Specified target vertex "
+                                                                                  + target
+                                                                                  + " is not part of graph "
+                                                                                  + g);
+        if (g.containsVertex(source) == false) throw new IllegalArgumentException("Specified source vertex "
+                                                                                  + source
+                                                                                  + " is not part of graph "
+                                                                                  + g);
+
+        Set<V> targets = new HashSet<V>();
+        targets.add(target);
+        Map<V,Number> distanceMap = getDistanceMap(source, targets);
+        return distanceMap.get(target);
+    }
+
+    /**
+     * Returns a {@code Map} from each element {@code t} of {@code targets} to the shortest-path distance from
+     * {@code source} to {@code t}.
+     */
+    public Map<V,Number> getDistanceMap(V source, Collection<V> targets) {
+        if (g.containsVertex(source) == false) throw new IllegalArgumentException("Specified source vertex "
+                                                                                  + source
+                                                                                  + " is not part of graph "
+                                                                                  + g);
+        if (targets.size() > max_targets) throw new IllegalArgumentException(
+                "size of target set exceeds maximum " + "number of targets allowed: " + this.max_targets);
+
+        Map<V,Number> distanceMap = singleSourceShortestPath(source, targets,
+            Math.min(g.getVertexCount(), max_targets));
+        if (!cached) reset(source);
+
+        return distanceMap;
+    }
+
+    /**
+     * <p>
+     * Returns a <code>LinkedHashMap</code> which maps each vertex in the graph (including the
+     * <code>source</code> vertex) to its distance from the <code>source</code> vertex. The map's iterator
+     * will return the elements in order of increasing distance from <code>source</code>.
+     * </p>
+     * 
+     * <p>
+     * The size of the map returned will be the number of vertices reachable from <code>source</code>.
+     * </p>
+     * 
+     * @see #getDistanceMap(Object,int)
+     * @see #getDistance(Object,Object)
+     * @param source
+     *            the vertex from which distances are measured
+     */
+    public Map<V,Number> getDistanceMap(V source) {
+        return getDistanceMap(source, Math.min(g.getVertexCount(), max_targets));
+    }
+
+    /**
+     * <p>
+     * Returns a <code>LinkedHashMap</code> which maps each of the closest <code>numDist</code> vertices to
+     * the <code>source</code> vertex in the graph (including the <code>source</code> vertex) to its distance
+     * from the <code>source</code> vertex. Throws an <code>IllegalArgumentException</code> if
+     * <code>source</code> is not in this instance's graph, or if <code>numDests</code> is either less than 1
+     * or greater than the number of vertices in the graph.
+     * </p>
+     * 
+     * <p>
+     * The size of the map returned will be the smaller of <code>numDests</code> and the number of vertices
+     * reachable from <code>source</code>.
+     * 
+     * @see #getDistanceMap(Object)
+     * @see #getDistance(Object,Object)
+     * @param source
+     *            the vertex from which distances are measured
+     * @param numDests
+     *            the number of vertices for which to measure distances
+     */
+    public LinkedHashMap<V,Number> getDistanceMap(V source, int numDests) {
+
+        if (g.getVertices().contains(source) == false) {
+            throw new IllegalArgumentException("Specified source vertex " + source + " is not part of graph "
+                                               + g);
+
+        }
+        if (numDests < 1 || numDests > g.getVertexCount()) throw new IllegalArgumentException(
+                "numDests must be >= 1 " + "and <= g.numVertices()");
+
+        if (numDests > max_targets) throw new IllegalArgumentException("numDests must be <= the maximum "
+                                                                       + "number of targets allowed: "
+                                                                       + this.max_targets);
+
+        LinkedHashMap<V,Number> distanceMap = singleSourceShortestPath(source, null, numDests);
+
+        if (!cached) reset(source);
+
+        return distanceMap;
+    }
+
+    /**
+     * Allows the user to specify the maximum distance that this instance will calculate. Any vertices past
+     * this distance will effectively be unreachable from the source, in the sense that the algorithm will not
+     * calculate the distance to any vertices which are farther away than this distance. A negative value for
+     * <code>max_dist</code> will ensure that no further distances are calculated.
+     * 
+     * <p>
+     * This can be useful for limiting the amount of time and space used by this algorithm if the graph is
+     * very large.
+     * </p>
+     * 
+     * <p>
+     * Note: if this instance has already calculated distances greater than <code>max_dist</code>, and the
+     * results are cached, those results will still be valid and available; this limit applies only to
+     * subsequent distance calculations.
+     * </p>
+     * 
+     * @see #setMaxTargets(int)
+     */
+    public void setMaxDistance(double max_dist) {
+        this.max_distance = max_dist;
+        for (V v : sourceMap.keySet()) {
+            SourceData sd = sourceMap.get(v);
+            sd.reached_max = (this.max_distance <= sd.dist_reached) || (sd.distances.size() >= max_targets);
+        }
+    }
+
+    /**
+     * Allows the user to specify the maximum number of target vertices per source vertex for which this
+     * instance will calculate distances. Once this threshold is reached, any further vertices will
+     * effectively be unreachable from the source, in the sense that the algorithm will not calculate the
+     * distance to any more vertices. A negative value for <code>max_targets</code> will ensure that no
+     * further distances are calculated.
+     * 
+     * <p>
+     * This can be useful for limiting the amount of time and space used by this algorithm if the graph is
+     * very large.
+     * </p>
+     * 
+     * <p>
+     * Note: if this instance has already calculated distances to a greater number of targets than
+     * <code>max_targets</code>, and the results are cached, those results will still be valid and available;
+     * this limit applies only to subsequent distance calculations.
+     * </p>
+     * 
+     * @see #setMaxDistance(double)
+     */
+    public void setMaxTargets(int max_targets) {
+        this.max_targets = max_targets;
+        for (V v : sourceMap.keySet()) {
+            SourceData sd = sourceMap.get(v);
+            sd.reached_max = (this.max_distance <= sd.dist_reached) || (sd.distances.size() >= max_targets);
+        }
+    }
+
+    /**
+     * Clears all stored distances for this instance. Should be called whenever the graph is modified (edge
+     * weights changed or edges added/removed). If the user knows that some currently calculated distances are
+     * unaffected by a change, <code>reset(V)</code> may be appropriate instead.
+     * 
+     * @see #reset(Object)
+     */
+    public void reset() {
+        sourceMap = new HashMap<V,SourceData>();
+    }
+
+    /**
+     * Specifies whether or not this instance of <code>DijkstraShortestPath</code> should cache its results
+     * (final and partial) for future reference.
+     * 
+     * @param enable
+     *            <code>true</code> if the results are to be cached, and <code>false</code> otherwise
+     */
+    public void enableCaching(boolean enable) {
+        this.cached = enable;
+    }
+
+    /**
+     * Clears all stored distances for the specified source vertex <code>source</code>. Should be called
+     * whenever the stored distances from this vertex are invalidated by changes to the graph.
+     * 
+     * @see #reset()
+     */
+    public void reset(V source) {
+        sourceMap.put(source, null);
+    }
+
+    /**
+     * Compares according to distances, so that the BinaryHeap knows how to order the tree.
+     */
+    protected static class VertexComparator<V> implements Comparator<V> {
+        private Map<V,Number> distances;
+
+        protected VertexComparator(Map<V,Number> distances) {
+            this.distances = distances;
+        }
+
+        public int compare(V o1, V o2) {
+            return ((Double) distances.get(o1)).compareTo((Double) distances.get(o2));
+        }
+    }
+
+    /**
+     * For a given source vertex, holds the estimated and final distances, tentative and final assignments of
+     * incoming edges on the shortest path from the source vertex, and a priority queue (ordered by estimated
+     * distance) of the vertices for which distances are unknown.
+     * 
+     * @author Joshua O'Madadhain
+     */
+    protected class SourceData {
+        protected LinkedHashMap<V,Number> distances;
+        protected Map<V,Number> estimatedDistances;
+        protected MapBinaryHeap<V> unknownVertices;
+        protected boolean reached_max = false;
+        protected double dist_reached = 0;
+
+        protected SourceData(V source) {
+            distances = new LinkedHashMap<V,Number>();
+            estimatedDistances = new HashMap<V,Number>();
+            unknownVertices = new MapBinaryHeap<V>(new VertexComparator<V>(estimatedDistances));
+
+            sourceMap.put(source, this);
+
+            // initialize priority queue
+            estimatedDistances.put(source, new Double(0)); // distance from source to itself is 0
+            unknownVertices.add(source);
+            reached_max = false;
+            dist_reached = 0;
+        }
+
+        protected Map.Entry<V,Number> getNextVertex() {
+            V v = unknownVertices.remove();
+            Double dist = (Double) estimatedDistances.remove(v);
+            distances.put(v, dist);
+            return new BasicMapEntry<V,Number>(v, dist);
+        }
+
+        protected void update(V dest, E tentative_edge, double new_dist) {
+            estimatedDistances.put(dest, new_dist);
+            unknownVertices.update(dest);
+        }
+
+        protected void createRecord(V w, E e, double new_dist) {
+            estimatedDistances.put(w, new_dist);
+            unknownVertices.add(w);
+        }
+
+        protected void restoreVertex(V v, double dist) {
+            estimatedDistances.put(v, dist);
+            unknownVertices.add(v);
+            distances.remove(v);
+        }
+    }
+
+    public static interface Transformer<I,O> {
+
+        /**
+         * Transforms the input object (leaving it unchanged) into some output object.
+         * 
+         * @param input
+         *            the object to be transformed, should be left unchanged
+         * @return a transformed object
+         * @throws ClassCastException
+         *             (runtime) if the input is the wrong class
+         * @throws IllegalArgumentException
+         *             (runtime) if the input is invalid
+         * @throws FunctorException
+         *             (runtime) if the transform cannot be completed
+         */
+        public O transform(I input);
+
+    }
+
+    public static class ConstantTransformer<T> implements Transformer<Object,T> {
+
+        private T constant;
+
+        public ConstantTransformer(T constantToReturn) {
+            super();
+            constant = constantToReturn;
+        }
+
+        public T transform(Object input) {
+            return constant;
+        }
+
+    }
+}

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/FreebaseDisambiguatorEngine.java
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/FreebaseDisambiguatorEngine.java?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/FreebaseDisambiguatorEngine.java (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/FreebaseDisambiguatorEngine.java Thu Oct  3 15:13:35 2013
@@ -0,0 +1,383 @@
+package org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph;
+
+import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.ENHANCER_CONFIDENCE;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+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.engine.disambiguation.freebase.graph.constants.FreebaseDisambiguatorEngineConstants;
+import org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph.helper.FreebaseDisambiguatorEngineHelper;
+import org.apache.stanbol.enhancer.engine.disambiguation.mlt.DisambiguationData;
+import org.apache.stanbol.enhancer.engine.disambiguation.mlt.SavedEntity;
+import org.apache.stanbol.enhancer.engine.disambiguation.mlt.Suggestion;
+import org.apache.stanbol.enhancer.servicesapi.ContentItem;
+import org.apache.stanbol.enhancer.servicesapi.EngineException;
+import org.apache.stanbol.enhancer.servicesapi.EnhancementEngine;
+import org.apache.stanbol.enhancer.servicesapi.InvalidContentException;
+import org.apache.stanbol.enhancer.servicesapi.ServiceProperties;
+import org.apache.stanbol.enhancer.servicesapi.helper.ContentItemHelper;
+import org.apache.stanbol.enhancer.servicesapi.helper.EnhancementEngineHelper;
+import org.apache.stanbol.enhancer.servicesapi.impl.AbstractEnhancementEngine;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Graph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.neo4j.Neo4jGraph;
+
+@Component(immediate = true, metatype = true)
+@Service
+@Properties(value = {@Property(name = EnhancementEngine.PROPERTY_NAME, value = "freebase-disambiguation"),
+                     @Property(name = FreebaseDisambiguatorEngine.GRAPH_LOCATION)})
+public class FreebaseDisambiguatorEngine extends AbstractEnhancementEngine<IOException,RuntimeException>
+        implements EnhancementEngine, ServiceProperties {
+    public static final String GRAPH_LOCATION = "graph.location";
+
+    private static Logger log = LoggerFactory.getLogger(FreebaseDisambiguatorEngine.class);
+
+    /**
+     * The default value for the execution of this Engine. Currently set to
+     * {@link ServiceProperties#ORDERING_POST_PROCESSING} - 600.
+     * <p>
+     * This should ensure that this engines runs as one of the first engines of the post-processing phase
+     */
+    public static final Integer defaultOrder = ServiceProperties.ORDERING_POST_PROCESSING - 600;
+
+    /**
+     * The plain text might be required for determining the extraction context
+     */
+
+    public static final String PLAIN_TEXT_MIMETYPE = "text/plain";
+    /**
+     * Contains the only supported mime type {@link #PLAIN_TEXT_MIMETYPE}
+     */
+    public static final Set<String> SUPPORTED_MIMETYPES = Collections.singleton(PLAIN_TEXT_MIMETYPE);
+
+    /**
+     * <p>
+     * Graph (Neo4jGraph) containing the whole graph
+     * </p>
+     */
+    private Graph graph;
+
+    /*
+     * The following parameters describe the ratio of the original fise:confidence values and the
+     * disambiguation scores contributing to the final disambiguated fise:confidence
+     * 
+     * TODO: make configurable
+     */
+    /**
+     * Default ratio for Disambiguation (2.0)
+     */
+    public static final double DEFAULT_DISAMBIGUATION_RATIO = 2.0;
+    /**
+     * Default ratio for the original fise:confidence of suggested entities
+     */
+    public static final double DEFAULT_CONFIDENCE_RATIO = 1.0;
+
+    /**
+     * The weight for disambiguation scores <code>:= disRatio/(disRatio+confRatio)</code>
+     */
+    private double disambiguationWeight = DEFAULT_DISAMBIGUATION_RATIO
+                                          / (DEFAULT_DISAMBIGUATION_RATIO + DEFAULT_CONFIDENCE_RATIO);
+    /**
+     * The weight for the original confidence scores <code>:= confRatio/(disRatio+confRatio)</code>
+     */
+    private double confidenceWeight = DEFAULT_CONFIDENCE_RATIO
+                                      / (DEFAULT_DISAMBIGUATION_RATIO + DEFAULT_CONFIDENCE_RATIO);
+
+    /**
+     * The {@link LiteralFactory} used to create typed RDF literals
+     */
+    private final LiteralFactory literalFactory = LiteralFactory.getInstance();
+
+    /**
+     * Returns the properties containing the {@link ServiceProperties#ENHANCEMENT_ENGINE_ORDERING}
+     */
+    public Map<String,Object> getServiceProperties() {
+        return Collections.unmodifiableMap(Collections.singletonMap(ENHANCEMENT_ENGINE_ORDERING,
+            (Object) defaultOrder));
+    }
+
+    /**
+     * /**
+     * <p>
+     * Checks whether the current {@code ContentItem} can be enhanced or not
+     * </p>
+     * 
+     * @param ci
+     *            The ContentItem to be enhanced
+     * 
+     * @return An integer indicating whether the ContentItem can be enhanced or not. There are a few constants
+     *         that can be returned: CANNOT_ENHANCE, ENHANCE_SYNCHRONOUS, ENHANCE_ASYNC
+     */
+    public int canEnhance(ContentItem ci) throws EngineException {
+        // check if content is present
+        try {
+            if ((ContentItemHelper.getText(ci.getBlob()) == null)
+                || (ContentItemHelper.getText(ci.getBlob()).trim().isEmpty())) {
+                return CANNOT_ENHANCE;
+            }
+        } catch (IOException e) {
+            log.error("Failed to get the text for " + "enhancement of content: " + ci.getUri(), e);
+            throw new InvalidContentException(this, ci, e);
+        }
+        // default enhancement is synchronous enhancement
+        return ENHANCE_SYNCHRONOUS;
+    }
+
+    /**
+     * <p>
+     * This function first evaluates all the possible ambiguations of each text annotation detected. The ids
+     * of the referenced entities are used to check relations in the Freebase graph in order to obtain a new
+     * disambiguation score based on the relations between entities in the graph
+     * </p>
+     * 
+     * <p>
+     * The results obtained are used to calculate new confidence values which are updated in the metadata.
+     * </p>
+     */
+    public void computeEnhancements(ContentItem ci) throws EngineException {
+
+        MGraph metadata = ci.getMetadata();
+
+        // Read the data from the content item
+        DisambiguationData disData;
+        ci.getLock().readLock().lock();
+        try {
+            disData = DisambiguationData.createFromContentItem(ci);
+        } finally {
+            ci.getLock().readLock().unlock();
+        }
+
+        /*
+         * Disambiguation Steps
+         * 
+         * 1. Generate the sets of entities for each text annotation
+         * 
+         * 2. Generate all the possible solutions for the text. That means, generate the combination of
+         * entities of each set (cartesian product)
+         * 
+         * 3. Construct the subgraph from the whole graph using only the extracted entities
+         * 
+         * 4. Filter the possible solutions, removing those entities from each possible solution which are not
+         * valid, i.e isolated entities in the graph
+         * 
+         * 5. For each possible solution, calculate the shortest path between every pair of entities in it and
+         * store the disambiguation score for the possible solution
+         * 
+         * 6. For each entity annotation, modify the confidence value using the disambiguation score for the
+         * suggestion of the entity annotation
+         */
+
+        /*
+         * (1) Generating the Map TextAnnotation->List<UriRef EntityUri> to be used to generate the possible
+         * solutions using cartesian product (one element for each entity of every text annotation)
+         * 
+         * Generating the allEntities list to be used to generate the subgraph
+         */
+        List<UriRef> allEntities = new ArrayList<UriRef>();
+        Multimap<UriRef,Suggestion> taSuggestions = ArrayListMultimap.create();
+
+        for (UriRef textAnnotation : disData.textAnnotations.keySet()) {
+            SavedEntity savedEntity = disData.textAnnotations.get(textAnnotation);
+            for (Suggestion suggestion : savedEntity.getSuggestions()) {
+                taSuggestions.put(textAnnotation, suggestion);
+                allEntities.add(suggestion.getEntityUri());
+            }
+        }
+
+        /*
+         * (2) Generate possible solutions
+         */
+        Set<List<Suggestion>> possibleSolutions = FreebaseDisambiguatorEngineHelper
+                .generatePossibleSolutions(taSuggestions);
+
+        /*
+         * (3) Generating the subgraph
+         */
+        log.info("Generating Subgraph for current entities");
+        Graph subgraph = FreebaseDisambiguatorEngineHelper.generateSubgraph(this.graph, allEntities);
+        log.info("Subgraph generated");
+
+        /*
+         * Stops the disambiguation if the subgraph has no edges
+         */
+        if (!subgraph.getEdges().iterator().hasNext()) {
+            // Graph with all its vertices isolated, don't modify the confidence
+            log.info("Graph with all its vertices isolated, don't modify the confidence of EntityAnnotation's");
+            return;
+        }
+
+        this.dumpGraph(subgraph);
+
+        /*
+         * (4) Filter possible solutions;
+         */
+        possibleSolutions = FreebaseDisambiguatorEngineHelper.filterPossibleSolutions(possibleSolutions,
+            subgraph);
+
+        /*
+         * (5) Calculate the shortest-path between entities in the possible solution and modify the
+         * disambiguation score of each Suggestion
+         */
+
+        FreebaseDisambiguatorEngineHelper.calculateDisambiguationScores(possibleSolutions, subgraph, disData);
+
+        /*
+         * (6) Modify confidence values of the entity annotations
+         */
+        ci.getLock().writeLock().lock();
+        try {
+            this.disambiguateAndApplyResults(metadata, disData);
+        } finally {
+            ci.getLock().writeLock().unlock();
+        }
+
+    }
+
+    /**
+     * <p>
+     * Calculates the new confidence value for each Suggestion using the normalized disambiguation score of
+     * the Suggestion
+     * <p>
+     * Applies the disambiguation results to the enhancements, modifying the confidence value of the entity
+     * annotations
+     * </p>
+     * 
+     * @param metadata
+     *            the {@code MGraph} instance containing the enhancement triples
+     * @param disData
+     *            the {@code DisambiguationData} instance containing the Suggestion objects and their
+     *            normalized disambiguation scores
+     */
+    private void disambiguateAndApplyResults(MGraph metadata, DisambiguationData disData) {
+        for (SavedEntity savedEntity : disData.textAnnotations.values()) {
+            for (Suggestion suggestion : savedEntity.getSuggestions()) {
+
+                Double ns = suggestion.getNormalizedDisambiguationScore();
+                /*
+                 * Suggestions with null in disambiguated confidence means that they don't form part of any
+                 * possible solution so their confidence value won't change
+                 */
+                if (ns == null) {
+                    suggestion.setDisambiguatedConfidence(suggestion.getOriginalConfidnece());
+                    continue;
+                }
+
+                Double c = suggestion.getOriginalConfidnece() == null ? 0 : suggestion
+                        .getOriginalConfidnece();
+
+                Double dc = c * confidenceWeight + ns * disambiguationWeight;
+                suggestion.setDisambiguatedConfidence(dc);
+
+                if (suggestion.getDisambiguatedConfidence() != null) {
+                    // change the confidence
+                    log.info("Modifying confidence for "
+                             + suggestion.getEntityAnnotation().getUnicodeString() + " (Entity "
+                             + suggestion.getEntityUri().getUnicodeString() + ") -> Last confidence: "
+                             + suggestion.getOriginalConfidnece() + " - New confidence: "
+                             + suggestion.getDisambiguatedConfidence());
+                    EnhancementEngineHelper.set(metadata, suggestion.getEntityAnnotation(),
+                        ENHANCER_CONFIDENCE, suggestion.getDisambiguatedConfidence(), literalFactory);
+                    EnhancementEngineHelper.addContributingEngine(metadata, suggestion.getEntityAnnotation(),
+                        this);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * <p>
+     * Dump the graph to the log debug
+     * </p>
+     * 
+     * @param graph
+     *            the {@code Graph> to dump
+
+     */
+    private void dumpGraph(Graph graph) {
+        if (log.isDebugEnabled() || true) {
+            log.debug("Dumping graph");
+            for (Vertex vertex : graph.getVertices()) {
+                log.debug("Vertex "
+                          + vertex
+                          + " : "
+                          + vertex.getProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY));
+            }
+            for (Edge edge : graph.getEdges()) {
+                log.debug("Edge: " + edge);
+            }
+        }
+    }
+
+    /**
+     * Activate and read the properties
+     * 
+     * @param ce
+     *            the {@link ComponentContext}
+     */
+    @Activate
+    protected void activate(ComponentContext ce) throws ConfigurationException {
+        try {
+            super.activate(ce);
+            @SuppressWarnings("unchecked")
+            Dictionary<String,Object> properties = ce.getProperties();
+            // update the service URL if it is defined
+            // if (properties.get(FORMCEPT_SERVICE_URL) != null) {
+            // this.serviceURL = (String) properties.get(FORMCEPT_SERVICE_URL);
+            // }
+            if (properties.get(GRAPH_LOCATION) != null
+                && !((String) properties.get(GRAPH_LOCATION)).isEmpty()) {
+                String location = (String) properties.get(GRAPH_LOCATION);
+                log.info("Loading graph. Location: " + location);
+                this.graph = new Neo4jGraph(location);
+                log.info("Graph loaded");
+            } else throw new IOException(GRAPH_LOCATION
+                                         + " property is null or empty. Failed to initialize the engine");
+        } catch (IOException e) { // log
+            log.error("Failed to update the configuration");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    /**
+     * Deactivate
+     * 
+     * @param ce
+     *            the {@link ComponentContext}
+     */
+    @Deactivate
+    protected void deactivate(ComponentContext ce) {
+        try {
+            // Closing the graph
+            super.deactivate(ce);
+            if (this.graph != null) this.graph.shutdown();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+}

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/UndirectedGraphJung.java
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/UndirectedGraphJung.java?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/UndirectedGraphJung.java (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/UndirectedGraphJung.java Thu Oct  3 15:13:35 2013
@@ -0,0 +1,91 @@
+package org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Graph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.oupls.jung.GraphJung;
+
+/**
+ * <p>
+ * Custom implementation of GraphJung which allows the graph to be undirected, i.e, not taking into account
+ * the direction of the edges
+ * </p>
+ * 
+ * @author Antonio David Perez Morales <ad...@gmail.com>
+ * 
+ */
+public class UndirectedGraphJung extends GraphJung<Graph> {
+
+    /**
+     * <p>
+     * Default constructor
+     * </p>
+     * 
+     * @param graph
+     *            The {@code Graph} object to be used as raw graph for JUNG implementation
+     */
+    public UndirectedGraphJung(Graph graph) {
+        super(graph);
+    }
+
+    /**
+     * <p>
+     * Get the out edges for a vertex
+     * </p>
+     * <p>
+     * Returns the incoming and outgoing edges for the vertex
+     * </p>
+     * 
+     * @param vertex
+     *            The vertex
+     * @return The {@code Collection<Edge>} of edges
+     */
+    public Collection<Edge> getOutEdges(final Vertex vertex) {
+        return getEdgesForVertex(vertex);
+    }
+
+    /**
+     * <p>
+     * Get the in edges for a vertex
+     * </p>
+     * <p>
+     * Returns the incoming and outgoing edges for the vertex
+     * </p>
+     * 
+     * @param vertex
+     *            The vertex
+     * @return The {@code Collection<Edge>} of edges
+     */
+    public Collection<Edge> getInEdges(Vertex vertex) {
+        return getEdgesForVertex(vertex);
+    }
+
+    /**
+     * <p>
+     * Gets all the edges for a vertex, both incoming and outgoing edges
+     * </p>
+     * 
+     * @param vertex
+     *            The vertex
+     * @return The {@code Collection<Edge>} of edges
+     * 
+     */
+    private Collection<Edge> getEdgesForVertex(Vertex vertex) {
+        final Iterable<Edge> itty = vertex.getEdges(Direction.BOTH);
+        if (itty instanceof Collection) {
+            return (Collection<Edge>) itty;
+        } else {
+            final List<Edge> edges = new ArrayList<Edge>();
+            for (final Edge edge : itty) {
+                edges.add(edge);
+            }
+            return edges;
+        }
+    }
+
+}

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/constants/FreebaseDisambiguatorEngineConstants.java
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/constants/FreebaseDisambiguatorEngineConstants.java?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/constants/FreebaseDisambiguatorEngineConstants.java (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/constants/FreebaseDisambiguatorEngineConstants.java Thu Oct  3 15:13:35 2013
@@ -0,0 +1,36 @@
+package org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph.constants;
+
+/**
+ * <p>
+ * Class containing the constants used by the Freebase Disambiguator Engine
+ * </p>
+ * 
+ * @author Antonio David Perez Morales <ad...@gmail.com>
+ * 
+ */
+public class FreebaseDisambiguatorEngineConstants {
+    /**
+     * Property in a Vertex to put the URI
+     */
+    public static final String VERTEX_ENTITY_URI_PROPERTY = "URI";
+
+    /**
+     * Edge label representing direct connections
+     */
+    public static final String DIRECT_CONNECTION_EDGE_LABEL = "direct-connection";
+
+    /**
+     * Edge label representing mediated connections
+     */
+    public static final String MEDIATED_CONNECTION_EDGE_LABEL = "mediated-connection";
+
+    /**
+     * Edge property containing the property used for generate an index for the edges
+     */
+    public static final String EDGE_KEY_VERTICES_CONNECTED_PROPERTY = "vertices.connected";
+
+    /**
+     * Edge property used to store the calculated weight in the subgraph
+     */
+    public static final String WEIGHT_EDGE_PROPERTY = "weight";
+}

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/helper/FreebaseDisambiguatorEngineHelper.java
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/helper/FreebaseDisambiguatorEngineHelper.java?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/helper/FreebaseDisambiguatorEngineHelper.java (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/java/org/apache/stanbol/enhancer/engine/disambiguation/freebase/graph/helper/FreebaseDisambiguatorEngineHelper.java Thu Oct  3 15:13:35 2013
@@ -0,0 +1,453 @@
+package org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph.helper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.log4j.Logger;
+import org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph.CustomDijkstraDistance;
+import org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph.UndirectedGraphJung;
+import org.apache.stanbol.enhancer.engine.disambiguation.freebase.graph.constants.FreebaseDisambiguatorEngineConstants;
+import org.apache.stanbol.enhancer.engine.disambiguation.mlt.DisambiguationData;
+import org.apache.stanbol.enhancer.engine.disambiguation.mlt.SavedEntity;
+import org.apache.stanbol.enhancer.engine.disambiguation.mlt.Suggestion;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Table;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Graph;
+import com.tinkerpop.blueprints.KeyIndexableGraph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+
+/**
+ * <p>
+ * Helper class with utility methods for FreebaseDisambiguatorEngine
+ * </p>
+ * 
+ * @author Antonio David Perez Morales <ad...@gmail.com>
+ * 
+ */
+public class FreebaseDisambiguatorEngineHelper {
+    private static Logger log = Logger.getLogger(FreebaseDisambiguatorEngineHelper.class);
+
+    /**
+     * <p>
+     * Generates the possible solutions. It means, generating all the possible combinations between the
+     * suggested entities for each text annotation
+     * </p>
+     * <p>
+     * It uses the cartesian product between sets to obtain them
+     * </p>
+     * <p>
+     * For example:
+     * 
+     * <pre>
+     * - TextAnnotation A -> Suggestions : [1,2]
+     *  - TextAnnotation B -> Suggestions : [3,4]
+     *  - TextAnnotation C -> Suggestions : [5]
+     * 
+     * - Result: [1,3,5] , [1,4,5] , [2,3,5] , [2,4,5]
+     * 
+     * </p>
+     * 
+     * @param textAnnotationSuggestions
+     * @return
+     */
+    public static Set<List<Suggestion>> generatePossibleSolutions(Multimap<UriRef,Suggestion> textAnnotationSuggestions) {
+        List<Set<Suggestion>> allSets = new ArrayList<Set<Suggestion>>();
+        for (UriRef ref : textAnnotationSuggestions.keySet()) {
+            allSets.add(ImmutableSet.copyOf(textAnnotationSuggestions.get(ref)));
+        }
+
+        Set<List<Suggestion>> possibleSolutions = Sets.cartesianProduct(allSets);
+
+        return possibleSolutions;
+    }
+
+    /**
+     * <p>
+     * Generates a subgraph containing only the given entities and their relations
+     * </p>
+     * 
+     * @param graph
+     *            The {@code Graph} containing the whole graph
+     * @param entities
+     *            The {@code List<UriRef>} containing the entities to be used to generate the subgraph
+     * @return a {@code Graph} instance containing the subgraph
+     */
+    public static Graph generateSubgraph(Graph graph, List<UriRef> entities) {
+        KeyIndexableGraph subgraph = new TinkerGraph();
+        UriRef[] ents = entities.toArray(new UriRef[0]);
+
+        int size = ents.length;
+        Map<UriRef,Vertex> targetMap = new HashMap<UriRef,Vertex>();
+        Map<UriRef,Vertex> sourceMap = new HashMap<UriRef,Vertex>();
+        for (int i = 0; i < size; i++) {
+            Iterator<Vertex> itv = graph.getVertices(
+                FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY, ents[i].getUnicodeString())
+                    .iterator();
+            if (itv.hasNext()) {
+                Vertex newVertex = subgraph.addVertex(null);
+                sourceMap.put(ents[i], itv.next());
+                targetMap.put(ents[i], newVertex);
+                newVertex.setProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY,
+                    ents[i].getUnicodeString());
+            }
+        }
+
+        for (int i = 0; i < size - 1; i++) {
+            for (int j = i + 1; j < size; j++) {
+                Vertex source = sourceMap.get(ents[i]);
+                Vertex target = sourceMap.get(ents[j]);
+                if (source == null || target == null) continue;
+
+                Iterator<Edge> ite = graph
+                        .getEdges(
+                            FreebaseDisambiguatorEngineConstants.EDGE_KEY_VERTICES_CONNECTED_PROPERTY,
+                            (String) source
+                                    .getProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY)
+                                    + "|"
+                                    + target.getProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY))
+                        .iterator();
+                Edge originalEdge = null;
+                while (ite.hasNext()) {
+                    originalEdge = ite.next();
+                    if (originalEdge.getLabel().equals(
+                        FreebaseDisambiguatorEngineConstants.DIRECT_CONNECTION_EDGE_LABEL)) break;
+
+                }
+
+                if (originalEdge == null) {
+                    ite = graph
+                            .getEdges(
+                                FreebaseDisambiguatorEngineConstants.EDGE_KEY_VERTICES_CONNECTED_PROPERTY,
+                                (String) target
+                                        .getProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY)
+                                        + "|"
+                                        + source.getProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY))
+                            .iterator();
+
+                    while (ite.hasNext()) {
+                        originalEdge = ite.next();
+                        if (originalEdge.getLabel().equals(
+                            FreebaseDisambiguatorEngineConstants.DIRECT_CONNECTION_EDGE_LABEL)) break;
+                    }
+                }
+
+                if (originalEdge != null) {
+                    log.info("Creating edge between " + targetMap.get(ents[i]).getProperty("URI") + " and "
+                             + targetMap.get(ents[j]).getProperty("URI") + " from the original edge "
+                             + originalEdge);
+                    Edge newEdge = subgraph.addEdge(null, targetMap.get(ents[i]), targetMap.get(ents[j]),
+                        originalEdge.getLabel());
+                    Double weight = 0.0;
+                    for (String edgeProperty : originalEdge.getPropertyKeys()) {
+                        if (!edgeProperty.contains(".")
+                            && originalEdge.getProperty(edgeProperty) instanceof Integer) weight += (Integer) originalEdge
+                                .getProperty(edgeProperty);
+                    }
+
+                    if (originalEdge.getLabel().equals(
+                        FreebaseDisambiguatorEngineConstants.DIRECT_CONNECTION_EDGE_LABEL)) weight = weight * 10;
+                    else weight = weight / 10;
+
+                    newEdge.setProperty(FreebaseDisambiguatorEngineConstants.WEIGHT_EDGE_PROPERTY, weight);
+                }
+
+                /*
+                 * for (Edge e : iterable) {
+                 * 
+                 * repetitions++; if (e.getVertex(Direction.IN).equals(target) ||
+                 * e.getVertex(Direction.OUT).equals(target)) { Edge newEdge = subgraph.addEdge(null,
+                 * targetMap.get(ents[i]), targetMap.get(ents[j]), "connection"); int weight = 0; for (String
+                 * edgeProperty : e.getPropertyKeys()) { if (!edgeProperty.contains(".") &&
+                 * e.getProperty(edgeProperty) instanceof Integer) weight += (Integer)
+                 * e.getProperty(edgeProperty); }
+                 * 
+                 * newEdge.setProperty("weight", weight); break; } }
+                 */
+
+            }
+        }
+
+        return subgraph;
+    }
+
+    /**
+     * <p>
+     * Generates a subgraph containing only the given entities and their relations
+     * </p>
+     * 
+     * @param graph
+     *            The {@code Graph} containing the whole graph
+     * @param entities
+     *            The {@code List<UriRef>} containing the entities to be used to generate the subgraph
+     * @return a {@code Graph} instance containing the subgraph
+     */
+    public static Graph generateSubgraphBak(Graph graph, List<UriRef> entities) {
+
+        // Using in-memory graph with Key Index support
+
+        KeyIndexableGraph subgraph = new TinkerGraph();
+        UriRef[] ents = entities.toArray(new UriRef[0]);
+
+        subgraph.createKeyIndex(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY, Vertex.class);
+
+        int size = ents.length;
+        Map<UriRef,Vertex> targetMap = new HashMap<UriRef,Vertex>();
+        Map<UriRef,Vertex> sourceMap = new HashMap<UriRef,Vertex>();
+        for (int i = 0; i < size; i++) {
+            Iterator<Vertex> itv = graph.getVertices(
+                FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY, ents[i].getUnicodeString())
+                    .iterator();
+            if (itv.hasNext()) {
+                Vertex newVertex = subgraph.addVertex(null);
+                sourceMap.put(ents[i], itv.next());
+                targetMap.put(ents[i], newVertex);
+                newVertex.setProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY,
+                    ents[i].getUnicodeString());
+            }
+        }
+
+        for (int i = 0; i < size - 1; i++) {
+            Vertex source = sourceMap.get(ents[i]);
+            UriRef[] dest = new UriRef[size - i - 1];
+            System.arraycopy(ents, i + 1, dest, 0, size - i - 1);
+
+            Iterable<Edge> iterable = source.getEdges(Direction.BOTH,
+                FreebaseDisambiguatorEngineConstants.DIRECT_CONNECTION_EDGE_LABEL,
+                FreebaseDisambiguatorEngineConstants.MEDIATED_CONNECTION_EDGE_LABEL);
+            int processed = 0;
+            int max = dest.length;
+            for (Edge e : iterable) {
+                if (processed == max || dest.length == 0) break;
+
+                for (int j = 0; j < dest.length; j++) {
+                    Vertex target = sourceMap.get(dest[j]);
+                    if (e.getVertex(Direction.IN).equals(target) || e.getVertex(Direction.OUT).equals(target)) {
+                        Edge newEdge = subgraph.addEdge(null, targetMap.get(ents[i]), targetMap.get(dest[j]),
+                            e.getLabel());
+                        Double weight = 0.0;
+                        for (String edgeProperty : e.getPropertyKeys()) {
+                            if (!edgeProperty.contains(".") && e.getProperty(edgeProperty) instanceof Integer) weight += (Integer) e
+                                    .getProperty(edgeProperty);
+                        }
+
+                        /*
+                         * if(e.getLabel().equals("direct-connection")) weight = weight/10; else weight =
+                         * weight*10;
+                         */
+
+                        newEdge.setProperty(FreebaseDisambiguatorEngineConstants.WEIGHT_EDGE_PROPERTY, weight);
+                        processed++;
+
+                        if (j + 1 == dest.length) dest = new UriRef[0];
+                        else dest = Arrays.copyOfRange(dest, j + 1, dest.length);
+
+                        break;
+                    }
+                }
+            }
+
+        }
+
+        return subgraph;
+    }
+
+    /**
+     * <p>
+     * Filter the possible solutions removing those entities which are isolated in the possible solution
+     * </p>
+     * 
+     * @param possibleSolutions
+     *            The {@code Set<List<Suggestion>>} instance containing the possible solutions
+     * 
+     * @param graph
+     *            The {@code Graph} object containing the graph to be queried
+     * 
+     * @return The {@code Set<List<Suggestion>>} instance containing the filtered possible solutions
+     * 
+     */
+    public static Set<List<Suggestion>> filterPossibleSolutions(Set<List<Suggestion>> possibleSolutions,
+                                                                Graph graph) {
+
+        Map<Suggestion,Boolean> toFilter = new HashMap<Suggestion,Boolean>();
+        Set<List<Suggestion>> filtered = Sets.newHashSet();
+
+        for (List<Suggestion> possibleSolution : possibleSolutions) {
+            List<Suggestion> filteredPossibleSolution = Lists.newArrayList();
+
+            for (Suggestion suggestion : possibleSolution) {
+                if (toFilter.containsKey(suggestion)) {
+                    if (toFilter.get(suggestion).equals(true)) continue;
+                    else filteredPossibleSolution.add(suggestion);
+                } else {
+                    Iterator<Vertex> itv = graph.getVertices(
+                        FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY,
+                        suggestion.getEntityUri().getUnicodeString()).iterator();
+                    if (itv.hasNext()) {
+                        Vertex v = itv.next();
+
+                        if (!v.getEdges(Direction.BOTH).iterator().hasNext()) {
+                            // Isolated Vertex. Filter the subGraph
+                            toFilter.put(suggestion, true);
+                            log.debug("Isolated Vertex "
+                                      + v.getProperty(FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY)
+                                      + ". Filtering");
+                        } else {
+                            filteredPossibleSolution.add(suggestion);
+                            toFilter.put(suggestion, false);
+                        }
+                    } else {
+                        // No vertex exists. Filter the subGraph
+                        toFilter.put(suggestion, true);
+                        log.debug("No vertex exists with URI " + suggestion.getEntityUri().getUnicodeString());
+                    }
+
+                }
+            }
+
+            if (filteredPossibleSolution.size() > 1) filtered.add(filteredPossibleSolution);
+        }
+
+        return filtered;
+    }
+
+    /**
+     * <p>
+     * Calculates the disambiguation score for each possible solution using the Dijkstra Algorithm
+     * (shortest-path)
+     * </p>
+     * 
+     * @param possibleSolutions
+     *            The {@code Set<List<Suggestion>>} object containing the possible solutions to be used
+     * @param graph
+     *            the {@code Graph} object containing the graph to use
+     */
+    public static void calculateDisambiguationScores(Set<List<Suggestion>> possibleSolutions,
+                                                     Graph graph,
+                                                     DisambiguationData disData) {
+
+        UndirectedGraphJung undirectedGraph = new UndirectedGraphJung(graph);
+        CustomDijkstraDistance<Vertex,Edge> dijkstra = new CustomDijkstraDistance<Vertex,Edge>(
+                undirectedGraph, new CustomDijkstraDistance.Transformer<Edge,Double>() {
+                    public Double transform(Edge input) {
+                        return (1.0 / (Double) input
+                                .getProperty(FreebaseDisambiguatorEngineConstants.WEIGHT_EDGE_PROPERTY));
+                    }
+                });
+
+        // For normalization purposes
+        Double maxDisambiguationScore = 0.0;
+        Double minDisambiguationScore = Double.MAX_VALUE;
+
+        /*
+         * Storing the shortest path between each pair of vertices, both A -> B and B -> A, because we are
+         * using undirected graph
+         */
+        Table<Vertex,Vertex,Double> precalculatedDistances = HashBasedTable.create();
+
+        // Filter subgraphs;
+        for (List<Suggestion> posSol : possibleSolutions) {
+            log.info("Processing possible solution: " + posSol);
+
+            Suggestion[] sga = posSol.toArray(new Suggestion[0]);
+            int size = sga.length;
+            Vertex source, target = null;
+
+            Double notNormalizedDisambiguatonScore = 0.0;
+
+            for (int i = 0; i < size - 1; i++) {
+                for (int j = i + 1; j < size; j++) {
+                    Iterator<Vertex> itv = graph.getVertices(
+                        FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY,
+                        sga[i].getEntityUri().getUnicodeString()).iterator();
+                    Iterator<Vertex> itv2 = graph.getVertices(
+                        FreebaseDisambiguatorEngineConstants.VERTEX_ENTITY_URI_PROPERTY,
+                        sga[j].getEntityUri().getUnicodeString()).iterator();
+
+                    if (itv.hasNext()) source = itv.next();
+                    else break;
+
+                    if (itv2.hasNext()) target = itv2.next();
+                    else break;
+
+                    Double precalculated = precalculatedDistances.get(source, target);
+                    log.info("Precalculated between " + source.getProperty("URI") + " and "
+                             + target.getProperty("URI") + " is " + precalculated);
+                    if (precalculated == null) {
+                        log.info("Calculating distance");
+                        Number n = dijkstra.getDistance(source, target);
+                        n = n == null ? 0 : n;
+                        Double val = n.doubleValue();
+                        log.info("Storing precalculated between " + source.getProperty("URI") + " and "
+                                 + target.getProperty("URI") + " ->  " + val);
+                        precalculatedDistances.put(source, target, val);
+                        precalculatedDistances.put(target, source, val);
+                    }
+
+                    notNormalizedDisambiguatonScore += precalculatedDistances.get(source, target);
+                }
+            }
+
+            // Calculate the inverse to be used later in normalization
+            notNormalizedDisambiguatonScore = 1 / Math.log1p(notNormalizedDisambiguatonScore + 1);
+
+            if (notNormalizedDisambiguatonScore >= maxDisambiguationScore) maxDisambiguationScore = notNormalizedDisambiguatonScore;
+            if (notNormalizedDisambiguatonScore <= minDisambiguationScore) minDisambiguationScore = notNormalizedDisambiguatonScore;
+
+            /* Storing temporarily the not-normalized confidence for the suggestions */
+            for (Suggestion sugg : posSol) {
+                Double temp = sugg.getNormalizedDisambiguationScore();
+                if (temp == null) temp = 0.0;
+
+                // Change score only if the new score is greater than the old one
+                sugg.setNormalizedDisambiguationScore(notNormalizedDisambiguatonScore > temp ? notNormalizedDisambiguatonScore
+                        : temp);
+            }
+
+        }
+
+        if (minDisambiguationScore == Double.MAX_VALUE) minDisambiguationScore = 0.0;
+
+        /* Normalize confidences in the range of [0,1] for all Suggestion */
+        /*
+         * Those suggestion which don't belong to any possible solution won't have disambiguation score so,
+         * their confidence value won't change
+         */
+        for (SavedEntity entity : disData.textAnnotations.values()) {
+            for (Suggestion sugg : entity.getSuggestions()) {
+                if (sugg.getNormalizedDisambiguationScore() == null) {
+                    sugg.setNormalizedDisambiguationScore(0.0);
+                    continue;
+                }
+                // If maxDisambiguationScore equals to minDisambiguationScore and equals to current
+                // disambiguation
+                // score, then set the max normalized value (1.0)
+                Double normalizedDisambiguationScore = sugg.getNormalizedDisambiguationScore().equals(
+                    maxDisambiguationScore)
+                                                       && maxDisambiguationScore
+                                                               .equals(minDisambiguationScore) ? 1.0
+                        : (sugg.getNormalizedDisambiguationScore() - minDisambiguationScore)
+                          / (maxDisambiguationScore - minDisambiguationScore);
+
+                log.info(sugg.getEntityUri().getUnicodeString() + " -> Normalized disambiguation score: "
+                         + normalizedDisambiguationScore);
+
+                sugg.setNormalizedDisambiguationScore(normalizedDisambiguationScore);
+
+            }
+        }
+    }
+}

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-core/pom.xml
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-core/pom.xml?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-core/pom.xml (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-core/pom.xml Thu Oct  3 15:13:35 2013
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.tinkerpop.blueprints</groupId>
+		<artifactId>blueprints</artifactId>
+		<version>2.5.0-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<artifactId>blueprints-core</artifactId>
+	<url>http://blueprints.tinkerpop.com</url>
+	<name>Blueprints-Core</name>
+	<description>Core interfaces and utilities for Blueprints</description>
+	<dependencies>
+		<dependency>
+			<groupId>org.codehaus.jettison</groupId>
+			<artifactId>jettison</artifactId>
+			<version>1.3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.datatype</groupId>
+			<artifactId>jackson-datatype-json-org</artifactId>
+			<version>2.1.2</version>
+		</dependency>
+		<dependency>
+			<groupId>colt</groupId>
+			<artifactId>colt</artifactId>
+			<version>1.2.0</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>${junit.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-configuration</groupId>
+			<artifactId>commons-configuration</artifactId>
+			<version>1.6</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<directory>${basedir}/target</directory>
+		<finalName>${project.artifactId}-${project.version}</finalName>
+		<resources>
+			<resource>
+				<directory>${basedir}/src/main/resources
+                </directory>
+			</resource>
+		</resources>
+		<testResources>
+			<testResource>
+				<directory>${basedir}/src/test/resources
+                </directory>
+			</testResource>
+		</testResources>
+		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<version>2.3</version>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>attached</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<attach>false</attach>
+					<descriptors>
+						<descriptor>src/assembly/distribution.xml</descriptor>
+					</descriptors>
+					<finalName>${project.artifactId}-${project.version}</finalName>
+					<outputDirectory>target</outputDirectory>
+					<workDirectory>target/assembly/work</workDirectory>
+					<tarLongFileMode>warn</tarLongFileMode>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+					</archive>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>2.3.7</version>
+				<extensions>true</extensions>
+				<configuration>
+					<archive>
+						<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+					</archive>
+					<instructions>
+						<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+						<Bundle-Name>${project.artifactId}</Bundle-Name>
+						<Bundle-Version>${project.version}</Bundle-Version>
+						<Import-Package>!cern.colt.*, !com.fasterxml.jackson*,
+							!org.apache.commons.configuration*,*</Import-Package>
+					</instructions>
+				</configuration>
+				<executions>
+					<execution>
+						<id>bundle-manifest</id>
+						<phase>process-classes</phase>
+						<goals>
+							<goal>manifest</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

Added: stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-neo4j-graph/pom.xml
URL: http://svn.apache.org/viewvc/stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-neo4j-graph/pom.xml?rev=1528907&view=auto
==============================================================================
--- stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-neo4j-graph/pom.xml (added)
+++ stanbol/branches/disambiguation/enhancement-engines/freebase-disambiguation/src/main/resources/blueprints-neo4j-graph/pom.xml Thu Oct  3 15:13:35 2013
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.tinkerpop.blueprints</groupId>
+		<artifactId>blueprints</artifactId>
+		<version>2.5.0-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<artifactId>blueprints-neo4j-graph</artifactId>
+	<name>Blueprints-Neo4jGraph</name>
+	<description>Blueprints property graph implementation for the Neo4j graph database</description>
+	<properties>
+		<bundle.plugin.version>2.3.7</bundle.plugin.version>
+	</properties>
+	<dependencies>
+		<dependency>
+			<groupId>com.tinkerpop.blueprints</groupId>
+			<artifactId>blueprints-core</artifactId>
+			<version>${blueprints.version}</version>
+		</dependency>
+		<!--<dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j</artifactId> 
+			<version>1.9.2</version> <type>pom</type> </dependency> -->
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.osgi.core</artifactId>
+			<version>1.0.0</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.neo4j</groupId>
+			<artifactId>neo4j-ha</artifactId>
+			<version>1.9.2</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.neo4j</groupId>
+			<artifactId>neo4j-management</artifactId>
+			<version>1.9.2</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.tinkerpop.blueprints</groupId>
+			<artifactId>blueprints-test</artifactId>
+			<version>${blueprints.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.transaction</groupId>
+			<artifactId>jta</artifactId>
+			<version>1.1</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.tinkerpop.blueprints</groupId>
+			<artifactId>blueprints-graph-jung</artifactId>
+			<version>2.3.0</version>
+		</dependency>
+		<dependency>
+			<groupId>com.tinkerpop.gremlin</groupId>
+			<artifactId>gremlin-java</artifactId>
+			<version>2.3.0</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<directory>${basedir}/target</directory>
+		<finalName>${project.artifactId}-${project.version}</finalName>
+		<resources>
+			<resource>
+				<directory>${basedir}/src/main/resources
+                </directory>
+			</resource>
+		</resources>
+		<testResources>
+			<testResource>
+				<directory>${basedir}/src/test/resources
+                </directory>
+			</testResource>
+		</testResources>
+		<plugins>
+			<plugin>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+					</archive>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>${bundle.plugin.version}</version>
+				<extensions>true</extensions>
+				<configuration>
+					<archive>
+						<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+					</archive>
+					<instructions>
+						<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+						<Bundle-Name>${project.artifactId}</Bundle-Name>
+						<Bundle-Version>${project.version}</Bundle-Version>
+						<Bundle-Classpath>.</Bundle-Classpath>
+						<Import-Package>*;resolution:="optional"</Import-Package>
+						<Export-Package>edu.uci.ics.*, com.tinkerpop.blueprints.*</Export-Package>
+						<Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
+						<Embed-Directory>lib/</Embed-Directory>
+						<Embed-Transitive>true</Embed-Transitive>
+						<Include-Resource>{maven-dependencies}</Include-Resource>
+					</instructions>
+				</configuration>
+				<executions>
+					<execution>
+						<id>bundle-manifest</id>
+						<phase>process-classes</phase>
+						<goals>
+							<goal>manifest</goal>
+						</goals>
+					</execution>
+					<execution>
+						<id>bundle-bundle</id>
+						<phase>package</phase>
+						<goals>
+							<goal>bundle</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	<profiles>
+		<profile>
+			<id>create-osgi-bundles-from-dependencies</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.felix</groupId>
+						<artifactId>maven-bundle-plugin</artifactId>
+						<version>${bundle.plugin.version}</version>
+						<extensions>true</extensions>
+						<executions>
+							<execution>
+								<id>wrap-my-dependency</id>
+								<goals>
+									<goal>wrap</goal>
+								</goals>
+								<configuration>
+									<wrapImportPackage>!com.sun.tools</wrapImportPackage>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
+</project>