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);
+ }
+ }
+
+}