You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by al...@apache.org on 2012/10/05 17:35:30 UTC

svn commit: r1394594 [4/9] - in /stanbol/trunk: commons/authentication.basic/ commons/security/ contrib/reengineer/base/ contrib/reengineer/db/ contrib/reengineer/db/src/main/java/org/apache/stanbol/reengineer/db/ contrib/reengineer/db/src/test/java/or...

Added: stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/ClerezzaOntologyProvider.java
URL: http://svn.apache.org/viewvc/stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/ClerezzaOntologyProvider.java?rev=1394594&view=auto
==============================================================================
--- stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/ClerezzaOntologyProvider.java (added)
+++ stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/ClerezzaOntologyProvider.java Fri Oct  5 15:35:22 2012
@@ -0,0 +1,1453 @@
+/*
+ * 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.ontologymanager.multiplexer.clerezza.ontology;
+
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.APPENDED_TO_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.ENTRY_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_APPENDED_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_ONTOLOGY_IRI_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_SPACE_CORE_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_SPACE_CUSTOM_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_VERSION_IRI_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.IS_MANAGED_BY_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.IS_SPACE_CORE_OF_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.IS_SPACE_CUSTOM_OF_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.MANAGES_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.MAPS_TO_GRAPH_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.RETRIEVED_FROM_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.SCOPE_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.SESSION_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.SIZE_IN_TRIPLES_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary._NS_STANBOL_INTERNAL;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.TreeSet;
+
+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.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.access.EntityAlreadyExistsException;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.access.TcProvider;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.core.serializedform.Parser;
+import org.apache.clerezza.rdf.core.serializedform.UnsupportedFormatException;
+import org.apache.clerezza.rdf.ontologies.OWL;
+import org.apache.clerezza.rdf.ontologies.RDF;
+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.Property;
+import org.apache.felix.scr.annotations.PropertyOption;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.ReferenceStrategy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.stanbol.commons.indexedgraph.IndexedMGraph;
+import org.apache.stanbol.commons.owl.OWLOntologyManagerFactory;
+import org.apache.stanbol.commons.owl.PhonyIRIMapper;
+import org.apache.stanbol.commons.owl.transformation.OWLAPIToClerezzaConverter;
+import org.apache.stanbol.commons.owl.util.OWLUtils;
+import org.apache.stanbol.commons.owl.util.URIUtils;
+import org.apache.stanbol.commons.stanboltools.offline.OfflineMode;
+import org.apache.stanbol.ontologymanager.multiplexer.clerezza.collector.MGraphMultiplexer;
+import org.apache.stanbol.ontologymanager.servicesapi.OfflineConfiguration;
+import org.apache.stanbol.ontologymanager.servicesapi.OntologyNetworkConfiguration;
+import org.apache.stanbol.ontologymanager.servicesapi.collector.ImportManagementPolicy;
+import org.apache.stanbol.ontologymanager.servicesapi.io.Origin;
+import org.apache.stanbol.ontologymanager.servicesapi.ontology.Multiplexer;
+import org.apache.stanbol.ontologymanager.servicesapi.ontology.OntologyHandleException;
+import org.apache.stanbol.ontologymanager.servicesapi.ontology.OntologyProvider;
+import org.apache.stanbol.ontologymanager.servicesapi.ontology.OrphanOntologyKeyException;
+import org.apache.stanbol.ontologymanager.servicesapi.scope.Scope;
+import org.apache.stanbol.ontologymanager.servicesapi.session.Session;
+import org.apache.stanbol.ontologymanager.servicesapi.util.OntologyUtils;
+import org.osgi.service.component.ComponentContext;
+import org.semanticweb.owlapi.apibinding.OWLManager;
+import org.semanticweb.owlapi.model.AddImport;
+import org.semanticweb.owlapi.model.IRI;
+import org.semanticweb.owlapi.model.OWLDataFactory;
+import org.semanticweb.owlapi.model.OWLOntology;
+import org.semanticweb.owlapi.model.OWLOntologyChange;
+import org.semanticweb.owlapi.model.OWLOntologyCreationException;
+import org.semanticweb.owlapi.model.OWLOntologyID;
+import org.semanticweb.owlapi.model.OWLOntologyIRIMapper;
+import org.semanticweb.owlapi.model.OWLOntologyManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Clerezza-based ontology provider implementation. Whether it is persistent or in-memory depends on the
+ * {@link TcProvider} used.<br>
+ * <br>
+ * NOTE: in this implementation, the <code>preferredFormat</code> argument of the
+ * {@link #loadInStore(InputStream, String, boolean)} and {@link #loadInStore(IRI, String, boolean)} methods
+ * is not the only one to be tried when parsing an ontology, but merely the first one: should it fail, all
+ * other supported formats will be tried as a fallback.
+ * 
+ * @author alexdma
+ * 
+ */
+@Component(immediate = true, metatype = true)
+@Service({OntologyProvider.class,
+          org.apache.stanbol.ontologymanager.obsolete.api.ontology.OntologyProvider.class})
+public class ClerezzaOntologyProvider implements
+        org.apache.stanbol.ontologymanager.obsolete.api.ontology.OntologyProvider<TcProvider> {
+
+    /**
+     * Internally, the Clerezza ontology provider uses a reserved graph to store the associations between
+     * ontology IDs/physical IRIs and graph names. This graph is wrapped into an {@link OntologyToTcMapper}
+     * object.
+     * 
+     * @author alexdma
+     * 
+     */
+    private class OntologyToTcMapper {
+
+        private MGraph graph;
+
+        OntologyToTcMapper() {
+            if (store == null) throw new IllegalArgumentException("TcProvider cannot be null");
+            UriRef graphId = new UriRef(metaGraphId);
+            try {
+                graph = store.createMGraph(graphId);
+            } catch (EntityAlreadyExistsException e) {
+                graph = store.getMGraph(graphId);
+            }
+        }
+
+        void addMapping(OWLOntologyID ontologyReference, UriRef graphName) {
+            if (ontologyReference == null || ontologyReference.isAnonymous()) throw new IllegalArgumentException(
+                    "An anonymous ontology cannot be mapped. A non-anonymous ontology ID must be forged in these cases.");
+            Triple tType, tMaps, tHasOiri = null, tHasViri = null;
+            IRI ontologyIRI = ontologyReference.getOntologyIRI(), versionIri = ontologyReference
+                    .getVersionIRI();
+            UriRef entry = buildResource(ontologyReference);
+            tType = new TripleImpl(entry, RDF.type, ENTRY_URIREF);
+            tMaps = new TripleImpl(entry, MAPS_TO_GRAPH_URIREF, graphName);
+            LiteralFactory lf = LiteralFactory.getInstance();
+            tHasOiri = new TripleImpl(entry, HAS_ONTOLOGY_IRI_URIREF, lf.createTypedLiteral(new UriRef(
+                    ontologyIRI.toString())));
+            if (versionIri != null) tHasViri = new TripleImpl(entry, HAS_VERSION_IRI_URIREF,
+                    lf.createTypedLiteral(new UriRef(versionIri.toString())));
+            synchronized (graph) {
+                graph.add(tType);
+                graph.add(tMaps);
+                if (tHasViri != null) graph.add(tHasViri);
+                graph.add(tHasOiri);
+            }
+        }
+
+        OWLOntologyID buildPublicKey(final UriRef resource) {
+            // TODO desanitize?
+            LiteralFactory lf = LiteralFactory.getInstance();
+            IRI oiri = null, viri = null;
+            Iterator<Triple> it = graph.filter(resource, HAS_ONTOLOGY_IRI_URIREF, null);
+            if (it.hasNext()) {
+                UriRef s = null;
+                Resource obj = it.next().getObject();
+                if (obj instanceof UriRef) s = ((UriRef) obj);
+                else if (obj instanceof TypedLiteral) s = lf.createObject(UriRef.class, (TypedLiteral) obj);
+                oiri = IRI.create(s.getUnicodeString());
+            } else {
+                // Anonymous ontology? Decode the resource itself (which is not null)
+                return OntologyUtils.decode(resource.getUnicodeString());
+            }
+            it = graph.filter(resource, HAS_VERSION_IRI_URIREF, null);
+            if (it.hasNext()) {
+                UriRef s = null;
+                Resource obj = it.next().getObject();
+                if (obj instanceof UriRef) s = ((UriRef) obj);
+                else if (obj instanceof TypedLiteral) s = lf.createObject(UriRef.class, (TypedLiteral) obj);
+                viri = IRI.create(s.getUnicodeString());
+            }
+            if (viri == null) return new OWLOntologyID(oiri);
+            else return new OWLOntologyID(oiri, viri);
+        }
+
+        /**
+         * Creates an {@link UriRef} out of an {@link OWLOntologyID}, so it can be used as a storage key for
+         * the graph.
+         * 
+         * @param ontologyReference
+         * @return
+         */
+        UriRef buildResource(OWLOntologyID publicKey) {
+            /*
+             * The UriRef is of the form ontologyIRI[:::versionIRI] (TODO use something less conventional e.g.
+             * the string form of OWLOntologyID objects?)
+             */
+            TripleCollection meta = getMetaGraph(TripleCollection.class);
+            if (publicKey == null) throw new IllegalArgumentException(
+                    "Cannot build a UriRef resource on a null public key!");
+
+            // XXX should versionIRI also include the version IRI set by owners? Currently not
+
+            // Remember not to sanitize logical identifiers.
+            IRI ontologyIri = publicKey.getOntologyIRI(), versionIri = publicKey.getVersionIRI();
+            if (ontologyIri == null) throw new IllegalArgumentException(
+                    "Cannot build a UriRef resource on an anonymous public key!");
+
+            log.debug("Searching for a meta graph entry for public key:");
+            log.debug(" -- {}", publicKey);
+            UriRef match = null;
+            LiteralFactory lf = LiteralFactory.getInstance();
+            TypedLiteral oiri = lf.createTypedLiteral(new UriRef(ontologyIri.toString()));
+            TypedLiteral viri = versionIri == null ? null : lf.createTypedLiteral(new UriRef(versionIri
+                    .toString()));
+            for (Iterator<Triple> it = meta.filter(null, HAS_ONTOLOGY_IRI_URIREF, oiri); it.hasNext();) {
+                Resource subj = it.next().getSubject();
+                log.debug(" -- Ontology IRI match found. Scanning");
+                log.debug(" -- Resource : {}", subj);
+                if (!(subj instanceof UriRef)) {
+                    log.debug(" ---- (uncomparable: skipping...)");
+                    continue;
+                }
+                if (viri != null) {
+                    // Must find matching versionIRI
+                    if (meta.contains(new TripleImpl((UriRef) subj, HAS_VERSION_IRI_URIREF, viri))) {
+                        log.debug(" ---- Version IRI match!");
+                        match = (UriRef) subj;
+                        break; // Found
+                    } else {
+                        log.debug(" ---- Expected version IRI match not found.");
+                        continue; // There could be another with the right versionIRI.
+                    }
+
+                } else {
+                    // Must find unversioned resource
+                    if (meta.filter((UriRef) subj, HAS_VERSION_IRI_URIREF, null).hasNext()) {
+                        log.debug(" ---- Unexpected version IRI found. Skipping.");
+                        continue;
+                    } else {
+                        log.debug(" ---- Unversioned match!");
+                        match = (UriRef) subj;
+                        break; // Found
+                    }
+                }
+            }
+            log.debug("Matching UriRef in graph : {}", match);
+            if (match == null) {
+                return new UriRef(OntologyUtils.encode(publicKey));
+            } else {
+                return match;
+            }
+        }
+
+        UriRef getMapping(OWLOntologyID reference) {
+            Set<UriRef> aliases = new HashSet<UriRef>();
+            aliases.add(buildResource(reference));
+            for (OWLOntologyID alias : listAliases(reference))
+                aliases.add(buildResource(alias));
+            for (UriRef alias : aliases) {
+                // Logical mappings first.
+                Iterator<Triple> it = graph.filter(alias, MAPS_TO_GRAPH_URIREF, null);
+                while (it.hasNext()) {
+                    Resource obj = it.next().getObject();
+                    if (obj instanceof UriRef) return (UriRef) obj;
+                }
+                Literal litloc = LiteralFactory.getInstance().createTypedLiteral(
+                    new UriRef(alias.getUnicodeString()));
+                // Logical mappings failed, try physical mappings.
+                it = graph.filter(null, RETRIEVED_FROM_URIREF, litloc);
+                while (it.hasNext()) {
+                    Resource obj = it.next().getSubject();
+                    if (obj instanceof UriRef) return (UriRef) obj;
+                }
+            }
+            return null;
+        }
+
+        OWLOntologyID getReverseMapping(UriRef graphName) {
+            // Logical mappings first.
+            Iterator<Triple> it = graph.filter(null, MAPS_TO_GRAPH_URIREF, graphName);
+            while (it.hasNext()) {
+                Resource obj = it.next().getSubject();
+                if (obj instanceof UriRef) return buildPublicKey((UriRef) obj);
+            }
+            Literal litloc = LiteralFactory.getInstance().createTypedLiteral(
+                new UriRef(graphName.getUnicodeString()));
+            // Logical mappings failed, try physical mappings.
+            it = graph.filter(null, RETRIEVED_FROM_URIREF, litloc);
+            while (it.hasNext()) {
+                Resource subj = it.next().getSubject();
+                if (subj instanceof UriRef) return buildPublicKey((UriRef) subj);
+
+            }
+            return null;
+        }
+
+        Set<OWLOntologyID> getVersions(IRI ontologyIri) {
+            if (ontologyIri == null) throw new IllegalArgumentException("Cannot get versions for a null IRI.");
+            Set<OWLOntologyID> keys = new HashSet<OWLOntologyID>();
+            LiteralFactory lf = LiteralFactory.getInstance();
+            TypedLiteral iri = lf.createTypedLiteral(new UriRef(ontologyIri.toString()));
+            // Exclude aliases.
+            for (Iterator<Triple> it = graph.filter(null, HAS_ONTOLOGY_IRI_URIREF, iri); it.hasNext();) {
+                Resource sub = it.next().getSubject();
+                if (sub instanceof UriRef) keys.add(buildPublicKey((UriRef) sub));
+            }
+            // Also check for physical locations
+            for (Iterator<Triple> it = graph.filter(null, RETRIEVED_FROM_URIREF, iri); it.hasNext();) {
+                Resource sub = it.next().getSubject();
+                if (sub instanceof UriRef) keys.add(buildPublicKey((UriRef) sub));
+            }
+            return keys;
+        }
+
+        void mapLocator(IRI locator, UriRef graphName) {
+            if (graphName == null) throw new IllegalArgumentException("A null graph name is not allowed.");
+            // Null locator is a legal argument, will remove all locator mappings from the supplied graph
+            Set<Triple> remove = new HashSet<Triple>();
+            for (Iterator<Triple> nodes = graph.filter(graphName, null, null); nodes.hasNext();) {
+                Triple t = nodes.next();
+                // isOntology |= RDF.type.equals(t.getPredicate()) && OWL.Ontology.equals(t.getObject());
+                if (RETRIEVED_FROM_URIREF.equals(t.getPredicate())) remove.add(t);
+            }
+            graph.removeAll(remove);
+            if (locator != null) {
+                Literal litloc = LiteralFactory.getInstance().createTypedLiteral(
+                    new UriRef(locator.toString()));
+                graph.add(new TripleImpl(graphName, RETRIEVED_FROM_URIREF, litloc));
+            }
+        }
+
+        void registerOntologyDeletion(OWLOntologyID publicKey) {
+            Set<Triple> toRemove = new HashSet<Triple>();
+            Set<OWLOntologyID> aliases = listAliases(publicKey);
+            aliases.add(publicKey);
+            for (OWLOntologyID alias : aliases) {
+                UriRef ontologyId = buildResource(alias);
+                // Also removes aliases and dependencies.
+                // XXX Too extreme?
+                for (Iterator<Triple> it = graph.filter(ontologyId, null, null); it.hasNext();)
+                    toRemove.add(it.next());
+                for (Iterator<Triple> it = graph.filter(null, null, ontologyId); it.hasNext();)
+                    toRemove.add(it.next());
+            }
+            graph.removeAll(toRemove);
+        }
+
+        void removeMapping(OWLOntologyID ontologyReference) {
+            Iterator<Triple> it = graph.filter(buildResource(ontologyReference), MAPS_TO_GRAPH_URIREF, null);
+            // I expect a concurrent modification exception here, but we can deal with it later.
+            while (it.hasNext())
+                graph.remove(it.next());
+        }
+
+        void setMapping(OWLOntologyID ontologyReference, UriRef graphName) {
+            removeMapping(ontologyReference);
+            addMapping(ontologyReference, graphName);
+        }
+
+    }
+
+    private static final String _GRAPH_PREFIX_DEFAULT = "ontonet";
+
+    private static final ImportManagementPolicy _IMPORT_POLICY_DEFAULT = ImportManagementPolicy.PRESERVE;
+
+    private static final String _META_GRAPH_ID_DEFAULT = "org.apache.stanbol.ontologymanager.ontonet";
+
+    private static final boolean _RESOLVE_IMPORTS_DEFAULT = true;
+
+    protected Multiplexer descriptor = null;
+
+    @Property(name = OntologyProvider.IMPORT_POLICY, options = {
+                                                                @PropertyOption(value = '%'
+                                                                                        + OntologyProvider.IMPORT_POLICY
+                                                                                        + ".option.merge", name = "MERGE"),
+                                                                @PropertyOption(value = '%'
+                                                                                        + OntologyProvider.IMPORT_POLICY
+                                                                                        + ".option.flatten", name = "FLATTEN"),
+                                                                @PropertyOption(value = '%'
+                                                                                        + OntologyProvider.IMPORT_POLICY
+                                                                                        + ".option.preserve", name = "PRESERVE")}, value = "PRESERVE")
+    private String importPolicyString;
+
+    /**
+     * Maps ontology IRIs (logical or physical if the ontology is anonymous) to Clerezza storage keys i.e.
+     * graph names.
+     */
+    private OntologyToTcMapper keymap = null;
+
+    private Logger log = LoggerFactory.getLogger(getClass());
+
+    private List<OWLOntologyIRIMapper> mappers = new ArrayList<OWLOntologyIRIMapper>();
+
+    @Property(name = OntologyProvider.META_GRAPH_ID, value = _META_GRAPH_ID_DEFAULT)
+    protected String metaGraphId = _META_GRAPH_ID_DEFAULT;
+
+    @Reference
+    OfflineConfiguration offlineConfig;
+
+    /**
+     * The {@link OfflineMode} is used by Stanbol to indicate that no external service should be referenced.
+     * For this engine that means it is necessary to check if the used {@link ReferencedSite} can operate
+     * offline or not.
+     * 
+     * @see #enableOfflineMode(OfflineMode)
+     * @see #disableOfflineMode(OfflineMode)
+     */
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC, bind = "enableOfflineMode", unbind = "disableOfflineMode", strategy = ReferenceStrategy.EVENT)
+    private OfflineMode offlineMode;
+
+    @Reference
+    Parser parser;
+
+    @Property(name = OntologyProvider.GRAPH_PREFIX, value = _GRAPH_PREFIX_DEFAULT)
+    protected String prefix = _GRAPH_PREFIX_DEFAULT;
+
+    @Property(name = OntologyProvider.RESOLVE_IMPORTS, boolValue = _RESOLVE_IMPORTS_DEFAULT)
+    protected boolean resolveImports = _RESOLVE_IMPORTS_DEFAULT;
+
+    /*
+     * Do not use SCR reference here: this might be different from the registered WeightedTcProvider services
+     * : when supplied, it overrides TcManager
+     */
+    private TcProvider store = null;
+
+    private Class<?>[] supported = null;
+
+    @Reference
+    private TcManager tcManager;
+
+    /**
+     * This default constructor is <b>only</b> intended to be used by the OSGI environment with Service
+     * Component Runtime support.
+     * <p>
+     * DO NOT USE to manually create instances - the ClerezzaOntologyProvider instances do need to be
+     * configured! YOU NEED TO USE {} or its overloads, to parse the configuration and then initialise the
+     * rule store if running outside an OSGI environment.
+     */
+    public ClerezzaOntologyProvider() {
+        supported = new Class<?>[] {MGraph.class, TripleCollection.class, OWLOntology.class};
+    }
+
+    public ClerezzaOntologyProvider(TcProvider store, OfflineConfiguration offline, Parser parser) {
+        this();
+
+        this.offlineConfig = offline;
+        // Re-assign the TcManager if no store is supplied
+        if (store == null) store = TcManager.getInstance();
+        this.store = store;
+        if (this.tcManager == null) this.tcManager = TcManager.getInstance();
+        // Same for the parser
+        if (parser == null) this.parser = Parser.getInstance();
+        else this.parser = parser;
+
+        activate(new Hashtable<String,Object>());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Activate
+    protected void activate(ComponentContext context) {
+        log.info("in {} activate with context {}", getClass(), context);
+        if (context == null) {
+            throw new IllegalStateException("No valid" + ComponentContext.class + " parsed in activate!");
+        }
+        activate((Dictionary<String,Object>) context.getProperties());
+    }
+
+    protected void activate(Dictionary<String,Object> configuration) {
+
+        // Check if the TcManager should be set as the store
+        if (store == null) store = tcManager;
+
+        // Parse configuration.
+        metaGraphId = (String) (configuration.get(OntologyProvider.META_GRAPH_ID));
+        if (metaGraphId == null) metaGraphId = _META_GRAPH_ID_DEFAULT; // Should be already assigned though
+
+        // This call will also create the metadata graph.
+        keymap = new OntologyToTcMapper();
+        descriptor = new MGraphMultiplexer(keymap.graph);
+
+        // Parse configuration.
+        prefix = (String) (configuration.get(OntologyProvider.GRAPH_PREFIX));
+        if (prefix == null) prefix = _GRAPH_PREFIX_DEFAULT; // Should be already assigned though
+
+        try {
+            resolveImports = (Boolean) (configuration.get(OntologyProvider.RESOLVE_IMPORTS));
+        } catch (Exception ex) {
+            resolveImports = _RESOLVE_IMPORTS_DEFAULT; // Should be already assigned though
+        }
+
+        Object importPolicy = configuration.get(OntologyProvider.IMPORT_POLICY);
+        if (importPolicy == null) {
+            this.importPolicyString = _IMPORT_POLICY_DEFAULT.name();
+        } else {
+            this.importPolicyString = importPolicy.toString();
+        }
+
+        // TODO replace with DataFileProvider ?
+        final IRI[] offlineResources;
+        if (this.offlineConfig != null) {
+            List<IRI> paths = offlineConfig.getOntologySourceLocations();
+            if (paths != null) offlineResources = paths.toArray(new IRI[0]);
+            // There are no offline paths.
+            else offlineResources = new IRI[0];
+        }
+        // There's no offline configuration at all.
+        else offlineResources = new IRI[0];
+        this.mappers = OWLOntologyManagerFactory.getMappers(offlineResources);
+
+    }
+
+    @Override
+    public boolean addAlias(OWLOntologyID primaryKey, OWLOntologyID alias) {
+        log.info("Adding alias for ontology entry.");
+        log.info(" ... Primary key : {}", primaryKey);
+        log.info(" ... Alias : {}", alias);
+        // TODO check that they do not map to two different ontologies.
+        // XXX a SPARQL query could come in handy.
+        // Nothing to do but defer to the meta graph,
+        new MetaGraphManager(tcManager, keymap.graph).updateAddAlias(primaryKey, alias);
+        log.info(" ... DONE.");
+        return true;
+    }
+
+    @Override
+    public OWLOntologyID createBlankOntologyEntry(OWLOntologyID publicKey) {
+        log.info("Creating new orphan entry.");
+        log.info(" ... Public key : {}", publicKey);
+        /*
+         * TODO keep this object from being created on every call once we get totally rid of the
+         * OntologyToTcMapper class.
+         */
+        MetaGraphManager metaMgr = new MetaGraphManager(tcManager, keymap.graph);
+        metaMgr.updateCreateEntry(publicKey);
+        log.info(" ... DONE.");
+        return publicKey;
+    }
+
+    @Deactivate
+    protected void deactivate(ComponentContext context) {
+        log.info("in {} deactivate with context {}", getClass(), context);
+    }
+
+    /**
+     * Called by the ConfigurationAdmin to unbind the {@link #offlineMode} if the service becomes unavailable
+     * 
+     * @param mode
+     */
+    protected final void disableOfflineMode(OfflineMode mode) {
+        this.offlineMode = null;
+    }
+
+    /**
+     * Called by the ConfigurationAdmin to bind the {@link #offlineMode} if the service becomes available
+     * 
+     * @param mode
+     */
+    protected final void enableOfflineMode(OfflineMode mode) {
+        this.offlineMode = mode;
+    }
+
+    /**
+     * Fills a reverse stack of import targets for the graph identified by key <tt>importing</tt>. The import
+     * tree is visited in <i>pre-order</i> and the stack is filled accordingly. Optionally, a second stack can
+     * be supplied to store only the level 1 imports. This can be used for preserving the original import tree
+     * structure.<br>
+     * <br>
+     * TODO there should be a more space-efficient implementation.
+     * 
+     * @param importing
+     *            the key of the root graph, which will be at the bottom of every list.
+     * @param reverseImports
+     *            the list that will store all import target keys in pre-order.
+     * @param level1Imports
+     *            a second list that will store the level 1 import target keys, and is not passed to recursive
+     *            calls. Will be ignored if null.
+     */
+    private void fillImportsReverse(OWLOntologyID importing,
+                                    List<OWLOntologyID> reverseImports,
+                                    List<OWLOntologyID> level1Imports) {
+        log.debug("Filling reverse imports for {}", importing);
+
+        // Add the importing ontology first
+        reverseImports.add(importing);
+        if (level1Imports != null) level1Imports.add(importing);
+
+        // Get the graph and explore its imports
+        TripleCollection graph // store.getTriples(importing);
+        = getStoredOntology(/* getPublicKey */(importing), MGraph.class, false);
+        Iterator<Triple> it = graph.filter(null, RDF.type, OWL.Ontology);
+        if (!it.hasNext()) return;
+        Iterator<Triple> it2 = graph.filter(it.next().getSubject(), OWL.imports, null);
+        while (it2.hasNext()) {
+            // obj is the *original* import target
+            Resource obj = it2.next().getObject();
+            if (obj instanceof UriRef) {
+                // Right now getKey() is returning the "private" storage ID
+                String key = getKey(IRI.create(((UriRef) obj).getUnicodeString()));
+                // TODO this will not be needed when getKey() and getPublicKey() return the proper public key.
+                OWLOntologyID oid = keymap.getReverseMapping(new UriRef(key));
+                // Check used for breaking cycles in the import graph.
+                // (Unoptimized, should not use contains() for stacks.)
+                if (!reverseImports.contains(oid)) {
+                    if (level1Imports != null) level1Imports.add(oid);
+                    fillImportsReverse(oid, reverseImports, null);
+                }
+            }
+        }
+    }
+
+    @Override
+    public ImportManagementPolicy getImportManagementPolicy() {
+        try {
+            return ImportManagementPolicy.valueOf(importPolicyString);
+        } catch (IllegalArgumentException e) {
+            log.warn("The value \""
+                     + importPolicyString
+                     + "\" configured as default ImportManagementPolicy does not match any value of the Enumeration! "
+                     + "Return the default policy as defined by the " + ImportManagementPolicy.class + ".");
+            return _IMPORT_POLICY_DEFAULT;
+        }
+    }
+
+    @Override
+    @Deprecated
+    public String getKey(IRI ontologyIri) {
+        // ontologyIri = URIUtils.sanitizeID(ontologyIri);
+        return getPublicKey(new OWLOntologyID(ontologyIri));
+    }
+
+    @Override
+    @Deprecated
+    public String getKey(OWLOntologyID ontologyId) {
+        return getPublicKey(ontologyId);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <O extends TripleCollection> O getMetaGraph(Class<O> returnType) {
+        if (!TripleCollection.class.isAssignableFrom(returnType)) throw new IllegalArgumentException(
+                "Only subtypes of " + TripleCollection.class + " are allowed.");
+        return (O) store.getTriples(new UriRef(metaGraphId));
+    }
+
+    @Override
+    @Deprecated
+    public OWLOntologyID getOntologyId(String storageKey) {
+        return keymap.getReverseMapping(new UriRef(storageKey));
+    }
+
+    public OntologyNetworkConfiguration getOntologyNetworkConfiguration() {
+        Map<String,Collection<OWLOntologyID>> coreOntologies = new HashMap<String,Collection<OWLOntologyID>>(), customOntologies = new HashMap<String,Collection<OWLOntologyID>>();
+        Map<String,Collection<String>> attachedScopes = new HashMap<String,Collection<String>>();
+        final TripleCollection meta = store.getTriples(new UriRef(metaGraphId));
+
+        // Scopes first
+        for (Iterator<Triple> it = meta.filter(null, RDF.type, SCOPE_URIREF); it.hasNext();) { // for each
+                                                                                               // scope
+            Triple ta = it.next();
+            NonLiteral sub = ta.getSubject();
+            if (sub instanceof UriRef) {
+                String s = ((UriRef) sub).getUnicodeString(), prefix = _NS_STANBOL_INTERNAL + Scope.shortName
+                                                                       + "/";
+                if (s.startsWith(prefix)) {
+                    String scopeId = s.substring(prefix.length());
+                    log.info("Rebuilding scope \"{}\".", scopeId);
+                    coreOntologies.put(scopeId, new TreeSet<OWLOntologyID>());
+                    customOntologies.put(scopeId, new TreeSet<OWLOntologyID>());
+                    UriRef core_ur = null, custom_ur = null;
+                    Resource r;
+                    // Check core space
+                    Iterator<Triple> it2 = meta.filter(sub, HAS_SPACE_CORE_URIREF, null);
+                    if (it2.hasNext()) {
+                        r = it2.next().getObject();
+                        if (r instanceof UriRef) core_ur = (UriRef) r;
+                    } else {
+                        it2 = meta.filter(null, IS_SPACE_CORE_OF_URIREF, sub);
+                        if (it2.hasNext()) {
+                            r = it2.next().getSubject();
+                            if (r instanceof UriRef) core_ur = (UriRef) r;
+                        }
+                    }
+
+                    // Check custom space
+                    it2 = meta.filter(sub, HAS_SPACE_CUSTOM_URIREF, null);
+                    if (it2.hasNext()) {
+                        r = it2.next().getObject();
+                        if (r instanceof UriRef) custom_ur = (UriRef) r;
+                    } else {
+                        it2 = meta.filter(null, IS_SPACE_CUSTOM_OF_URIREF, sub);
+                        if (it2.hasNext()) {
+                            r = it2.next().getSubject();
+                            if (r instanceof UriRef) custom_ur = (UriRef) r;
+                        }
+                    }
+
+                    // retrieve the ontologies
+                    if (core_ur != null) {
+                        for (it2 = meta.filter(core_ur, null, null); it2.hasNext();) {
+                            Triple t = it2.next();
+                            UriRef predicate = t.getPredicate();
+                            if (predicate.equals(MANAGES_URIREF)) {
+                                if (t.getObject() instanceof UriRef) coreOntologies.get(scopeId).add(
+                                    keymap.buildPublicKey((UriRef) t.getObject()) // FIXME must be very
+                                                                                  // temporary!
+                                        // ((UriRef) t.getObject()).getUnicodeString()
+                                        );
+                            }
+                        }
+                        for (it2 = meta.filter(null, null, core_ur); it2.hasNext();) {
+                            Triple t = it2.next();
+                            UriRef predicate = t.getPredicate();
+                            if (predicate.equals(IS_MANAGED_BY_URIREF)) {
+                                if (t.getSubject() instanceof UriRef) coreOntologies.get(scopeId).add(
+                                    keymap.buildPublicKey((UriRef) t.getSubject()) // FIXME must be very
+                                                                                   // temporary!
+                                        // ((UriRef) t.getSubject()).getUnicodeString()
+                                        );
+                            }
+                        }
+                    }
+                    if (custom_ur != null) {
+                        for (it2 = meta.filter(custom_ur, null, null); it2.hasNext();) {
+                            Triple t = it2.next();
+                            UriRef predicate = t.getPredicate();
+                            if (predicate.equals(MANAGES_URIREF)) {
+                                if (t.getObject() instanceof UriRef) customOntologies.get(scopeId).add(
+                                    keymap.buildPublicKey((UriRef) t.getObject()) // FIXME must be very
+                                                                                  // temporary!
+                                        // ((UriRef) t.getObject()).getUnicodeString()
+                                        );
+                            }
+                        }
+                        for (it2 = meta.filter(null, null, custom_ur); it2.hasNext();) {
+                            Triple t = it2.next();
+                            UriRef predicate = t.getPredicate();
+                            if (predicate.equals(IS_MANAGED_BY_URIREF)) {
+                                if (t.getSubject() instanceof UriRef) customOntologies.get(scopeId).add(
+                                    keymap.buildPublicKey((UriRef) t.getSubject()) // FIXME must be very
+                                                                                   // temporary!
+                                        // ((UriRef) t.getSubject()).getUnicodeString()
+                                        );
+                            }
+                        }
+                    }
+
+                }
+            }
+        }
+
+        // Sessions next
+        Map<String,Collection<OWLOntologyID>> sessionOntologies = new HashMap<String,Collection<OWLOntologyID>>();
+        for (Iterator<Triple> it = meta.filter(null, RDF.type, SESSION_URIREF); it.hasNext();) { // for each
+                                                                                                 // scope
+            Triple ta = it.next();
+            NonLiteral sub = ta.getSubject();
+            if (sub instanceof UriRef) {
+                UriRef ses_ur = (UriRef) sub;
+                String s = ((UriRef) sub).getUnicodeString();
+                String prefix = _NS_STANBOL_INTERNAL + Session.shortName + "/";
+                if (s.startsWith(prefix)) {
+                    String sessionId = s.substring(prefix.length());
+                    log.info("Rebuilding session \"{}\".", sessionId);
+                    sessionOntologies.put(sessionId, new TreeSet<OWLOntologyID>());
+                    attachedScopes.put(sessionId, new TreeSet<String>());
+                    // retrieve the ontologies
+                    if (ses_ur != null) {
+                        for (Iterator<Triple> it2 = meta.filter(ses_ur, MANAGES_URIREF, null); it2.hasNext();) {
+                            Resource obj = it2.next().getObject();
+                            if (obj instanceof UriRef) sessionOntologies.get(sessionId).add(
+                                keymap.buildPublicKey((UriRef) obj) // FIXME must be very temporary!
+                                    // ((UriRef) obj).getUnicodeString()
+                                    );
+
+                        }
+                        for (Iterator<Triple> it2 = meta.filter(null, IS_MANAGED_BY_URIREF, ses_ur); it2
+                                .hasNext();) {
+                            Resource subj = it2.next().getSubject();
+                            if (subj instanceof UriRef) sessionOntologies.get(sessionId).add(
+                                keymap.buildPublicKey((UriRef) subj) // FIXME must be very temporary!
+                                    // ((UriRef) subj).getUnicodeString()
+                                    );
+
+                        }
+                        for (Iterator<Triple> it2 = meta.filter(null, APPENDED_TO_URIREF, ses_ur); it2
+                                .hasNext();) {
+                            Resource subj = it2.next().getSubject();
+                            if (subj instanceof UriRef) {
+                                String s1 = ((UriRef) subj).getUnicodeString();
+                                String prefix1 = _NS_STANBOL_INTERNAL + Scope.shortName + "/";
+                                if (s1.startsWith(prefix1)) {
+                                    String scopeId = s1.substring(prefix1.length());
+                                    attachedScopes.get(sessionId).add(scopeId);
+                                }
+                            }
+                        }
+                        for (Iterator<Triple> it2 = meta.filter(ses_ur, HAS_APPENDED_URIREF, null); it2
+                                .hasNext();) {
+                            Resource obj = it2.next().getObject();
+                            if (obj instanceof UriRef) {
+                                String s1 = ((UriRef) obj).getUnicodeString();
+                                String prefix1 = _NS_STANBOL_INTERNAL + Scope.shortName + "/";
+                                if (s1.startsWith(prefix1)) {
+                                    String scopeId = s1.substring(prefix1.length());
+                                    attachedScopes.get(sessionId).add(scopeId);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return new OntologyNetworkConfiguration(coreOntologies, customOntologies, sessionOntologies,
+                attachedScopes);
+    }
+
+    @Override
+    public Multiplexer getOntologyNetworkDescriptor() {
+        return descriptor;
+    }
+
+    @Override
+    @Deprecated
+    public String getPublicKey(OWLOntologyID ontologyId) {
+        UriRef ur = keymap.getMapping(ontologyId);
+        log.debug("key for {} is {}", ontologyId, ur);
+        return (ur == null) ? null : ur.getUnicodeString();
+    }
+
+    @Override
+    @Deprecated
+    public Set<OWLOntologyID> getPublicKeys() {
+        return descriptor.getPublicKeys();
+    }
+
+    @Override
+    public TcProvider getStore() {
+        return store;
+    }
+
+    @Override
+    @Deprecated
+    public <O> O getStoredOntology(IRI reference, Class<O> returnType) {
+        // reference = URIUtils.sanitizeID(reference);
+        return getStoredOntology(new OWLOntologyID(reference), returnType);
+    }
+
+    @Override
+    @Deprecated
+    public <O> O getStoredOntology(IRI reference, Class<O> returnType, boolean merge) {
+        // reference = URIUtils.sanitizeID(reference);
+        return getStoredOntology(new OWLOntologyID(reference), returnType, merge);
+    }
+
+    @Override
+    public <O> O getStoredOntology(OWLOntologyID reference, Class<O> returnType) {
+        return getStoredOntology(reference, returnType, false);
+    }
+
+    @Override
+    public <O> O getStoredOntology(OWLOntologyID reference, Class<O> returnType, boolean merge) {
+
+        if (!hasOntology(reference)) throw new IllegalArgumentException("No ontology with public key "
+                                                                        + reference + " found.");
+        String key = /* getKey(reference); */
+        keymap.getMapping(reference).getUnicodeString();
+        if (key == null || key.isEmpty()) {
+            log.warn("No key found for IRI {}", reference);
+            return null;
+        } else return getStoredOntology(key, returnType, merge);
+    }
+
+    @Override
+    @Deprecated
+    public <O> O getStoredOntology(String key, Class<O> returnType) {
+        return getStoredOntology(key, returnType, false);
+    }
+
+    /**
+     * In this implementation the identifier is the Graph Name (e.g. ontonet::blabla)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    @Deprecated
+    public <O> O getStoredOntology(String identifier, Class<O> returnType, boolean forceMerge) {
+        if (identifier == null || identifier.isEmpty()) throw new IllegalArgumentException(
+                "Identifier cannot be null or empty.");
+        if (returnType == null) {
+            // Defaults to OWLOntology
+            returnType = (Class<O>) OWLOntology.class;
+            log.warn("No return type given for the ontology. Will return a {}", returnType.getCanonicalName());
+        }
+        boolean canDo = false;
+        for (Class<?> clazz : getSupportedReturnTypes())
+            if (clazz.isAssignableFrom(returnType)) {
+                canDo = true;
+                break;
+            }
+        if (!canDo) throw new UnsupportedOperationException(
+                "Return type " + returnType.getCanonicalName()
+                        + " is not allowed in this implementation. Only allowed return types are "
+                        + supported);
+
+        TripleCollection tc = store.getTriples(new UriRef(identifier));
+        if (tc == null) return null;
+        /*
+         * The ontology provider itself does not wrap the returned object into an in-memory graph, therefore
+         * any direct modifications will be propagated. Collectors should wrap them, though. To change this
+         * behaviour, uncomment the line below.
+         */
+        // tc = new SimpleMGraph(tc);
+
+        if (TripleCollection.class.equals(returnType) || MGraph.class.isAssignableFrom(returnType)) {
+            return returnType.cast(tc);
+        } else if (OWLOntology.class.isAssignableFrom(returnType)) {
+            try {
+                return (O) toOWLOntology(new UriRef(identifier), forceMerge);
+            } catch (OWLOntologyCreationException e) {
+                log.error(
+                    "Failed to return stored ontology " + identifier + " as type "
+                            + returnType.getCanonicalName(), e);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public Class<?>[] getSupportedReturnTypes() {
+        return supported;
+    }
+
+    @Override
+    @Deprecated
+    public boolean hasOntology(IRI ontologyIri) {
+        // ontologyIri = URIUtils.sanitizeID(ontologyIri);
+        return hasOntology(new OWLOntologyID(ontologyIri));
+    }
+
+    @Override
+    public boolean hasOntology(OWLOntologyID id) {
+        if (id == null || id.isAnonymous()) throw new IllegalArgumentException(
+                "Cannot check for an anonymous ontology.");
+        UriRef graphName = keymap.getMapping(id);
+        if (graphName == null) return false;
+        if (!store.listTripleCollections().contains(graphName)) throw new OrphanOntologyKeyException(id);
+        return true;
+    }
+
+    /**
+     * Returns <code>true</code> only if Stanbol operates in {@link OfflineMode}.
+     * 
+     * @return the offline state
+     */
+    protected final boolean isOfflineMode() {
+        return offlineMode != null;
+    }
+
+    /*
+     * (non-Javadoc) XXX see if we can use reasoners, either live or by caching materialisations.
+     * 
+     * @see
+     * org.apache.stanbol.ontologymanager.ontonet.api.ontology.OntologyProvider#listAliases(org.semanticweb
+     * .owlapi.model.OWLOntologyID)
+     */
+    @Override
+    public Set<OWLOntologyID> listAliases(OWLOntologyID publicKey) {
+        if (publicKey == null || publicKey.isAnonymous()) throw new IllegalArgumentException(
+                "Cannot locate aliases for null or anonymous public keys.");
+        Set<OWLOntologyID> aliases = new HashSet<OWLOntologyID>();
+        TripleCollection meta = getMetaGraph(TripleCollection.class);
+        UriRef ont = keymap.buildResource(publicKey);
+        // Forwards
+        for (Iterator<Triple> it = meta.filter(ont, OWL.sameAs, null); it.hasNext();) {
+            Resource r = it.next().getObject();
+            if (r instanceof UriRef) aliases.add(keymap.buildPublicKey((UriRef) r));
+        }
+        // Backwards
+        for (Iterator<Triple> it = meta.filter(null, OWL.sameAs, ont); it.hasNext();) {
+            Resource r = it.next().getSubject();
+            if (r instanceof UriRef) aliases.add(keymap.buildPublicKey((UriRef) r));
+        }
+        return aliases;
+    }
+
+    @Override
+    public Set<OWLOntologyID> listAllRegisteredEntries() {
+        Set<OWLOntologyID> result = new TreeSet<OWLOntologyID>();
+        // Add aliases
+        for (OWLOntologyID key : descriptor.getPublicKeys()) {
+            result.add(key);
+            for (OWLOntologyID alias : listAliases(key))
+                result.add(alias);
+        }
+        return result;
+    }
+
+    @Override
+    public SortedSet<OWLOntologyID> listOrphans() {
+        SortedSet<OWLOntologyID> result = new TreeSet<OWLOntologyID>();
+        for (OWLOntologyID key : descriptor.getPublicKeys()) {
+            UriRef graphName = keymap.getMapping(key);
+            if (graphName == null || !store.listTripleCollections().contains(graphName)) result.add(key);
+        }
+        return result;
+    }
+
+    @Override
+    public SortedSet<OWLOntologyID> listPrimaryKeys() {
+        // XXX here we should decide if non-registered Clerezza graphs should also be in the list.
+        SortedSet<OWLOntologyID> result = new TreeSet<OWLOntologyID>();
+        for (OWLOntologyID key : descriptor.getPublicKeys())
+            if (keymap.getMapping(key) != null) result.add(key);
+        return result;
+    }
+
+    @Override
+    public Set<OWLOntologyID> listVersions(IRI ontologyIri) {
+        return keymap.getVersions(ontologyIri);
+    }
+
+    @Override
+    public OWLOntologyID loadInStore(InputStream data,
+                                     String formatIdentifier,
+                                     boolean force,
+                                     Origin<?>... references) {
+        if (data == null) throw new IllegalArgumentException("No data to load ontologies from.");
+        if (formatIdentifier == null || formatIdentifier.trim().isEmpty()) throw new IllegalArgumentException(
+                "A non-null, non-blank format identifier is required for parsing the data stream.");
+        // This method only tries the supplied format once.
+        log.debug("Trying to parse data stream with format {}", formatIdentifier);
+        TripleCollection rdfData = parser.parse(data, formatIdentifier);
+        log.debug("SUCCESS format {}.", formatIdentifier);
+        return loadInStore(rdfData, force, references);
+    }
+
+    @Override
+    public OWLOntologyID loadInStore(final IRI ontologyIri,
+                                     String formatIdentifier,
+                                     boolean force,
+                                     Origin<?>... references) throws IOException {
+        log.debug("Loading {}", ontologyIri);
+        if (ontologyIri == null) throw new IllegalArgumentException("Ontology IRI cannot be null.");
+
+        IRI location = null;
+        if (force) location = null;
+        else for (OWLOntologyIRIMapper mapper : mappers) {
+            location = mapper.getDocumentIRI(ontologyIri);
+            if (location != null) break;
+        }
+        if (location == null) {
+            if (isOfflineMode()) throw new IllegalStateException(
+                    "Cannot retrieve " + ontologyIri + " while Stanbol is in offline mode. "
+                            + "No resource with that identifier was found locally.");
+            else location = ontologyIri;
+        }
+
+        log.info("found {} in {}", ontologyIri, location);
+
+        // Get ordered list of preferred/supported formats, or use the specified one.
+        List<String> supported = OntologyUtils.getPreferredSupportedFormats(parser.getSupportedFormats());
+        List<String> formats;
+        if (formatIdentifier == null || "".equals(formatIdentifier.trim())) formats = supported;
+        else {
+            formats = new LinkedList<String>();
+            // Pre-check supported format
+            if (supported.contains(formatIdentifier)) formats.add(formatIdentifier);
+            for (String sup : supported)
+                if (sup != null && !formats.contains(sup)) formats.add(sup);
+        }
+
+        for (String currentFormat : formats) {
+            try {
+                final URLConnection con = location.toURI().toURL().openConnection();
+                con.setRequestProperty("Accept", currentFormat);
+                final InputStream is = con.getInputStream();
+                if (is != null) {
+                    /*
+                     * We provide the current format, so the recursive call won't be trying to sort preferred
+                     * formats again. Also, we provide the ontologyIRI as the preferred key, since we already
+                     * know it.
+                     */
+                    OWLOntologyID key = loadInStore(is, currentFormat, force, Origin.create(ontologyIri));
+                    // If parsing failed, an exception will be thrown before getting here, so no risk.
+                    // if (key != null && !key.isEmpty()) setLocatorMapping(ontologyIri, key);
+                    return key;
+                }
+            } catch (UnsupportedFormatException e) {
+                log.debug("FAILURE format {} (unsupported). Trying next one.", currentFormat);
+                continue;
+            } catch (Exception e) {
+                log.debug("FAILURE format {} (parse error). Will try next one.", currentFormat);
+                continue;
+            }
+        }
+
+        // No parser worked, return null.
+        log.error("All parsers failed, giving up.");
+        return null;
+    }
+
+    @Override
+    public OWLOntologyID loadInStore(Object ontology, final boolean force, Origin<?>... origins) {
+
+        if (ontology == null) throw new IllegalArgumentException("No ontology supplied.");
+        long before = System.currentTimeMillis();
+
+        TripleCollection graph; // The final graph
+        TripleCollection rdfData; // The supplied ontology converted to TripleCollection
+
+        if (ontology instanceof OWLOntology) {
+            rdfData = OWLAPIToClerezzaConverter.owlOntologyToClerezzaMGraph((OWLOntology) ontology);
+        } else if (ontology instanceof TripleCollection) {
+            rdfData = (TripleCollection) ontology;
+        } else throw new UnsupportedOperationException(
+                "This ontology provider can only accept objects assignable to " + TripleCollection.class
+                        + " or " + OWLOntology.class);
+
+        // XXX Force is ignored for the content, but the imports?
+
+        // TODO Profile this method. Are we getting rid of rdfData after adding its triples?
+        OWLOntologyID publicKey = OWLUtils.extractOntologyID(rdfData);
+        if (publicKey == null) {
+            IRI z;
+            if (origins.length > 0 && origins[0] != null) {
+                Object reff = origins[0].getReference();
+                if (reff instanceof IRI) z = (IRI) reff; // No version IRI here
+                else if (reff instanceof UriRef) z = IRI.create(((UriRef) reff).getUnicodeString());
+                else z = IRI.create(getClass().getCanonicalName() + "-time:" + System.currentTimeMillis());
+            } else z = IRI.create(getClass().getCanonicalName() + "-time:" + System.currentTimeMillis());
+            publicKey = new OWLOntologyID(z);
+        }
+
+        // Check if it is possible to avoid reloading the ontology content from its source.
+        boolean mustLoad = true;
+        if (!force) {
+            Set<UriRef> stored = store.listTripleCollections();
+            if (origins.length > 0 && origins[0] != null && origins[0].getReference() instanceof UriRef) {
+                UriRef ref = (UriRef) origins[0].getReference();
+
+                if (stored.contains(ref)) {
+                    boolean condition = true; // Any failed check will make it false
+
+                    /*
+                     * Check if the stored Ontology ID (versionIRI included) matches matches that of the
+                     * ontology source. XXX note that anonymous ontologies should be considered a match... or
+                     * should they not?
+                     */
+                    OWLOntologyID idFromSrc = OWLUtils.extractOntologyID(rdfData);
+                    OWLOntologyID idFromStore = OWLUtils.extractOntologyID(store.getTriples(ref));
+                    condition &= (idFromSrc == null && idFromStore == null) || idFromSrc.equals(idFromStore);
+
+                    // Finally, a size check
+                    if (condition && rdfData instanceof TripleCollection) condition &= store.getTriples(ref)
+                            .size() == rdfData.size();
+
+                    mustLoad &= !condition;
+                }
+            }
+        }
+
+        // The policy here is to avoid copying the triples from a graph already in the store.
+        // FIXME not a good policy for graphs that change
+        String iri = null;
+        if (publicKey.getOntologyIRI() != null) iri = publicKey.getOntologyIRI().toString();
+        if (publicKey.getVersionIRI() != null) iri += ":::" + publicKey.getVersionIRI().toString();
+        // s will become the graph name
+        String s = (iri.startsWith(prefix + "::")) ? "" : (prefix + "::");
+        s += iri;
+        UriRef uriref;
+        if (mustLoad) {
+            uriref = new UriRef(URIUtils.sanitize(s));
+            log.debug("Storing ontology with graph ID {}", uriref);
+            try {
+                graph = store.createMGraph(uriref);
+            } catch (EntityAlreadyExistsException e) {
+                if (uriref.equals(e.getEntityName())) graph = store.getMGraph(uriref);
+                else graph = store.createMGraph(uriref);
+            }
+            graph.addAll(rdfData);
+        } else {
+            try {
+                uriref = (UriRef) origins[0].getReference();
+            } catch (ClassCastException cex) {
+                uriref = new UriRef(s);
+            }
+            log.debug("Graph with ID {} already in store. Default action is to skip storage.", origins[0]);
+            graph = store.getTriples(uriref);
+        }
+
+        // All is already sanitized by the time we get here.
+
+        // Now do the mappings
+        String mappedIds = "";
+        // Discard unconventional ontology IDs with only the version IRI
+        if (publicKey != null && publicKey.getOntologyIRI() != null) {
+            // Versioned or not, the real ID mapping is always added
+            keymap.setMapping(publicKey, uriref);
+            mappedIds += publicKey;
+            // TODO map unversioned ID as well?
+            Triple t = new TripleImpl(keymap.buildResource(publicKey), SIZE_IN_TRIPLES_URIREF, LiteralFactory
+                    .getInstance().createTypedLiteral(Integer.valueOf(rdfData.size())));
+            getMetaGraph(MGraph.class).add(t);
+        }
+        /*
+         * Make an ontology ID out of the originally supplied IRI (which might be the physical one and differ
+         * from the logical one!)
+         * 
+         * If we find out that it differs from the "real ID", we map this one too.
+         * 
+         * TODO how safe is this if there was a mapping earlier?
+         */
+
+        for (Origin<?> origin : origins)
+            if (origin != null) {
+                Object reff = origin.getReference();
+                if (reff instanceof IRI) {
+                    OWLOntologyID physical = new OWLOntologyID((IRI) reff);
+                    if (!physical.equals(publicKey)) {
+                        // keymap.setMapping(physical, uriref);
+                        new MetaGraphManager(tcManager, keymap.graph).updateAddAlias(publicKey, physical);
+                        mappedIds += " , " + physical;
+                    }
+                }
+            }
+
+        // Do this AFTER registering the ontology, otherwise import cycles will cause infinite loops.
+        if (resolveImports) {
+            // Scan resources of type owl:Ontology, but only get the first.
+            Iterator<Triple> it = graph.filter(null, RDF.type, OWL.Ontology);
+            if (it.hasNext()) {
+                // Scan import statements for the one owl:Ontology considered.
+                Iterator<Triple> it2 = graph.filter(it.next().getSubject(), OWL.imports, null);
+                while (it2.hasNext()) {
+                    Resource obj = it2.next().getObject();
+                    log.info("Resolving import target {}", obj);
+                    if (obj instanceof UriRef) try {
+                        // TODO try locals first
+                        UriRef target = (UriRef) obj;
+                        OWLOntologyID id = new OWLOntologyID(IRI.create(target.getUnicodeString()));
+                        if (keymap.getMapping(id) == null) { // Check if it's not there already.
+                            if (isOfflineMode()) throw new RuntimeException(
+                                    "Cannot load imported ontology " + obj
+                                            + " while Stanbol is in offline mode.");
+                            // TODO manage origins for imported ontologies too?
+                            OWLOntologyID id2 = loadInStore(IRI.create(((UriRef) obj).getUnicodeString()),
+                                null, false);
+                            if (id2 != null) id = id2;
+                            log.info("Import {} resolved.", obj);
+                            log.debug("");
+                        } else {
+                            log.info("Requested import already stored. Setting dependency only.");
+                        }
+                        descriptor.setDependency(publicKey, id);
+                    } catch (UnsupportedFormatException e) {
+                        log.warn("Failed to parse format for resource " + obj, e);
+                        // / XXX configure to continue?
+                    } catch (IOException e) {
+                        log.warn("Failed to load ontology from resource " + obj, e);
+                        // / XXX configure to continue?
+                    }
+                }
+            }
+        }
+
+        log.debug(" Ontology {}", mappedIds);
+        if (graph != null) log.debug(" ... ({} triples)", graph.size());
+        log.debug(" ... primary public key : {}", publicKey);
+        // log.debug("--- {}", URIUtils.sanitize(s));
+        log.debug("Time: {} ms", (System.currentTimeMillis() - before));
+        // return URIUtils.sanitize(s);
+        return publicKey;
+    }
+
+    @Override
+    public boolean removeOntology(OWLOntologyID publicKey) throws OntologyHandleException {
+
+        if (descriptor.getDependents(publicKey).isEmpty() && descriptor.getHandles(publicKey).isEmpty()) {
+
+            UriRef graphName = keymap.getMapping(publicKey);
+
+            // TODO propagate everything to the descriptor
+            descriptor.clearDependencies(publicKey); // release dependencies
+            keymap.registerOntologyDeletion(publicKey); // remove metadata
+
+            // Now the actual deletion
+            store.deleteTripleCollection(graphName);
+
+            return true;
+        } else throw new OntologyHandleException("There are ontologies or collectors depending on "
+                                                 + publicKey + "Those handles must be released first.");
+    }
+
+    @Override
+    public void setImportManagementPolicy(ImportManagementPolicy policy) {
+        if (policy == null) throw new IllegalArgumentException("Import management policy cannot be null.");
+        importPolicyString = policy.toString();
+    }
+
+    @Override
+    public void setLocatorMapping(IRI locator, OWLOntologyID publicKey) {
+        if (publicKey == null || publicKey.isAnonymous()) throw new IllegalArgumentException(
+                "key must be non-null and non-anonymous.");
+        log.info("Setting {} as the resource locator for ontology {}", locator, publicKey);
+        new MetaGraphManager(tcManager, keymap.graph).updateAddAlias(new OWLOntologyID(locator), publicKey);
+    }
+
+    @Override
+    public void setLocatorMapping(IRI locator, String key) {
+        if (key == null || key.isEmpty()) throw new IllegalArgumentException(
+                "key must be non-null and non-empty.");
+        if (!store.listTripleCollections().contains(new UriRef(key))) throw new IllegalArgumentException(
+                "No ontology found with storage key " + key);
+        if (locator == null) log
+                .warn(
+                    "Setting null locator for {}. This will remove all physical mappings for the corresponding graph.",
+                    key);
+        else log.info("Setting {} as the resource locator for ontology {}", locator, key);
+        keymap.mapLocator(locator, new UriRef(key));
+    }
+
+    /**
+     * 
+     * @param graphName
+     * @param forceMerge
+     *            if set to false, the selected import management policy will be applied.
+     * @return
+     * @throws OWLOntologyCreationException
+     */
+    protected OWLOntology toOWLOntology(UriRef graphName, boolean forceMerge) throws OWLOntologyCreationException {
+
+        log.debug("Exporting graph to OWLOntology");
+        log.debug(" -- Graph name : {}", graphName);
+        OWLOntologyManager mgr = OWLManager.createOWLOntologyManager();
+        // Never try to import
+        mgr.addIRIMapper(new PhonyIRIMapper(Collections.<IRI> emptySet()));
+
+        Set<OWLOntologyID> loaded = new HashSet<OWLOntologyID>();
+        TripleCollection graph = store.getTriples(graphName);
+        UriRef ontologyId = null;
+
+        // Get the id of this ontology.
+        Iterator<Triple> itt = graph.filter(null, RDF.type, OWL.Ontology);
+        if (itt.hasNext()) {
+            NonLiteral nl = itt.next().getSubject();
+            if (nl instanceof UriRef) ontologyId = (UriRef) nl;
+        }
+        List<OWLOntologyID> revImps = new Stack<OWLOntologyID>();
+        List<OWLOntologyID> lvl1 = new Stack<OWLOntologyID>();
+
+        fillImportsReverse(keymap.getReverseMapping(graphName), revImps, lvl1);
+
+        // If not set to merge (either by policy of by force), adopt the set import policy.
+        if (!forceMerge && !ImportManagementPolicy.MERGE.equals(getImportManagementPolicy())) {
+            OWLOntology o = OWLAPIToClerezzaConverter.clerezzaGraphToOWLOntology(graph, mgr);
+            // TODO make it not flat.
+            // Examining the reverse imports stack will flatten all imports.
+            List<OWLOntologyChange> changes = new ArrayList<OWLOntologyChange>();
+            OWLDataFactory df = OWLManager.getOWLDataFactory();
+
+            List<OWLOntologyID> listToUse;
+            switch (getImportManagementPolicy()) {
+                case FLATTEN:
+                    listToUse = revImps;
+                    break;
+                case PRESERVE:
+                    listToUse = lvl1;
+                    break;
+                default:
+                    listToUse = lvl1;
+                    break;
+            }
+
+            for (OWLOntologyID ref : listToUse)
+                if (!loaded.contains(ref) && !ref.equals(keymap.getReverseMapping(graphName))) {
+                    changes.add(new AddImport(o, df.getOWLImportsDeclaration(ref.getOntologyIRI())));
+                    loaded.add(ref);
+                }
+            o.getOWLOntologyManager().applyChanges(changes);
+            return o;
+        } else {
+            // Merge
+
+            // If there is just the root ontology, convert it straight away.
+            if (revImps.size() == 1 && revImps.contains(graphName)) {
+                OWLOntology o = OWLAPIToClerezzaConverter.clerezzaGraphToOWLOntology(graph, mgr);
+                return o;
+            }
+
+            // FIXME when there's more than one ontology, this way of merging them seems inefficient...
+            TripleCollection tempGraph = new IndexedMGraph();
+            // The set of triples that will be excluded from the merge
+            Set<Triple> exclusions = new HashSet<Triple>();
+            // Examine all reverse imports
+            for (OWLOntologyID ref : revImps)
+                if (!loaded.contains(ref)) {
+                    // Get the triples
+                    TripleCollection imported =
+                    // store.getTriples(ref);
+                    getStoredOntology(getKey(ref), MGraph.class, false);
+                    // For each owl:Ontology
+                    Iterator<Triple> remove = imported.filter(null, RDF.type, OWL.Ontology);
+                    while (remove.hasNext()) {
+                        NonLiteral subj = remove.next().getSubject();
+                        /*
+                         * If it's not the root ontology, trash all its triples. If the root ontology is
+                         * anonymous, all ontology annotations are to be trashed without distinction.
+                         */
+                        if (ontologyId == null || !subj.equals(ontologyId)) {
+                            Iterator<Triple> it = imported.filter(subj, null, null);
+                            while (it.hasNext()) {
+                                Triple t = it.next();
+                                exclusions.add(t);
+                            }
+                        }
+                    }
+
+                    Iterator<Triple> it = imported.iterator();
+                    while (it.hasNext()) {
+                        Triple t = it.next();
+                        if (!exclusions.contains(t)) tempGraph.add(t);
+                    }
+
+                    loaded.add(ref);
+                }
+            // Since they are all merged and import statements removed, there should be no risk of going
+            // online.
+            return OWLAPIToClerezzaConverter.clerezzaGraphToOWLOntology(tempGraph, mgr);
+        }
+    }
+
+}

Added: stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/MetaGraphManager.java
URL: http://svn.apache.org/viewvc/stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/MetaGraphManager.java?rev=1394594&view=auto
==============================================================================
--- stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/MetaGraphManager.java (added)
+++ stanbol/trunk/ontologymanager/multiplexer/clerezza/src/main/java/org/apache/stanbol/ontologymanager/multiplexer/clerezza/ontology/MetaGraphManager.java Fri Oct  5 15:35:22 2012
@@ -0,0 +1,144 @@
+/*
+ * 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.ontologymanager.multiplexer.clerezza.ontology;
+
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.ENTRY_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_ONTOLOGY_IRI_URIREF;
+import static org.apache.stanbol.ontologymanager.servicesapi.Vocabulary.HAS_VERSION_IRI_URIREF;
+
+import java.util.Iterator;
+
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TypedLiteral;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.ontologies.OWL;
+import org.apache.clerezza.rdf.ontologies.RDF;
+import org.apache.stanbol.ontologymanager.servicesapi.util.OntologyUtils;
+import org.semanticweb.owlapi.model.IRI;
+import org.semanticweb.owlapi.model.OWLOntologyID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ * Note that this class is not public.
+ * 
+ * @author alexdma
+ * 
+ */
+class MetaGraphManager {
+
+    private MGraph graph;
+
+    private TcManager tcManager;
+
+    private Logger log = LoggerFactory.getLogger(getClass());
+
+    public MetaGraphManager(TcManager tcManager, MGraph graph) {
+        this.tcManager = tcManager;
+        this.graph = graph;
+    }
+
+    protected UriRef buildResource(final OWLOntologyID publicKey) {
+        if (publicKey == null) throw new IllegalArgumentException(
+                "Cannot build a UriRef resource on a null public key!");
+        // The UriRef is of the form ontologyIRI[:::versionIRI] (TODO use something less conventional?)
+        // XXX should versionIRI also include the version IRI set by owners? Currently not
+
+        // Remember not to sanitize logical identifiers.
+        IRI ontologyIri = publicKey.getOntologyIRI(), versionIri = publicKey.getVersionIRI();
+        if (ontologyIri == null) throw new IllegalArgumentException(
+                "Cannot build a UriRef resource on an anonymous public key!");
+        log.debug("Searching for a meta graph entry for public key:");
+        log.debug(" -- {}", publicKey);
+        UriRef match = null;
+        LiteralFactory lf = LiteralFactory.getInstance();
+        TypedLiteral oiri = lf.createTypedLiteral(new UriRef(ontologyIri.toString()));
+        TypedLiteral viri = versionIri == null ? null : lf.createTypedLiteral(new UriRef(versionIri
+                .toString()));
+        for (Iterator<Triple> it = graph.filter(null, HAS_ONTOLOGY_IRI_URIREF, oiri); it.hasNext();) {
+            Resource subj = it.next().getSubject();
+            log.debug(" -- Ontology IRI match found. Scanning");
+            log.debug(" -- Resource : {}", subj);
+            if (!(subj instanceof UriRef)) {
+                log.debug(" ---- (uncomparable: skipping...)");
+                continue;
+            }
+            if (viri != null) {
+                // Must find matching versionIRI
+                if (graph.contains(new TripleImpl((UriRef) subj, HAS_VERSION_IRI_URIREF, viri))) {
+                    log.debug(" ---- Version IRI match!");
+                    match = (UriRef) subj;
+                    break; // Found
+                } else {
+                    log.debug(" ---- Expected version IRI match not found.");
+                    continue; // There could be another with the right versionIRI.
+                }
+
+            } else {
+                // Must find unversioned resource
+                if (graph.filter((UriRef) subj, HAS_VERSION_IRI_URIREF, null).hasNext()) {
+                    log.debug(" ---- Unexpected version IRI found. Skipping.");
+                    continue;
+                } else {
+                    log.debug(" ---- Unversioned match!");
+                    match = (UriRef) subj;
+                    break; // Found
+                }
+            }
+        }
+        log.debug("Matching UriRef in graph : {}", match);
+        if (match == null) return new UriRef(OntologyUtils.encode(publicKey));
+        else return match;
+
+    }
+
+    public void updateAddAlias(OWLOntologyID subject, OWLOntologyID object) {
+        // For now add both owl:sameAs statements
+        UriRef suben = buildResource(subject), oben = buildResource(object);
+        synchronized (graph) {
+            graph.add(new TripleImpl(suben, OWL.sameAs, oben));
+            graph.add(new TripleImpl(oben, OWL.sameAs, suben));
+        }
+        // XXX add the Entry typing later on, but if so give up on using owl:sameAs.
+    }
+
+    public void updateCreateEntry(OWLOntologyID publicKey) {
+        if (publicKey == null || publicKey.isAnonymous()) throw new IllegalArgumentException(
+                "An anonymous ontology cannot be mapped. A non-anonymous ontology ID must be forged in these cases.");
+        Triple tType, tHasOiri = null, tHasViri = null;
+        IRI ontologyIRI = publicKey.getOntologyIRI(), versionIri = publicKey.getVersionIRI();
+        UriRef entry = buildResource(publicKey);
+        tType = new TripleImpl(entry, RDF.type, ENTRY_URIREF);
+        LiteralFactory lf = LiteralFactory.getInstance();
+        tHasOiri = new TripleImpl(entry, HAS_ONTOLOGY_IRI_URIREF, lf.createTypedLiteral(new UriRef(
+                ontologyIRI.toString())));
+        if (versionIri != null) tHasViri = new TripleImpl(entry, HAS_VERSION_IRI_URIREF,
+                lf.createTypedLiteral(new UriRef(versionIri.toString())));
+        synchronized (graph) {
+            graph.add(tType);
+            if (tHasViri != null) graph.add(tHasViri);
+            graph.add(tHasOiri);
+        }
+    }
+
+}