/** * PODD is an OWL ontology database used for scientific project management * * Copyright (C) 2009-2013 The University Of Queensland * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. */ package com.github.podd.impl; import info.aduna.iteration.Iterations; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.openrdf.OpenRDFException; import org.openrdf.model.Literal; import org.openrdf.model.Model; import org.openrdf.model.Resource; import org.openrdf.model.Statement; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.model.impl.LinkedHashModel; import org.openrdf.model.util.ModelException; import org.openrdf.model.vocabulary.RDF; import org.openrdf.model.vocabulary.SESAME; import org.openrdf.repository.Repository; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.RepositoryResult; import org.openrdf.repository.config.RepositoryConfig; import org.openrdf.repository.config.RepositoryConfigException; import org.openrdf.repository.config.RepositoryImplConfig; import org.openrdf.repository.manager.LocalRepositoryManager; import org.openrdf.repository.manager.RemoteRepositoryManager; import org.openrdf.repository.manager.RepositoryManager; import org.openrdf.repository.sail.SailRepository; import org.openrdf.rio.RDFHandlerException; import org.openrdf.rio.helpers.StatementCollector; import org.openrdf.sail.federation.Federation; import org.openrdf.sail.memory.MemoryStore; import org.semanticweb.owlapi.model.OWLOntologyID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.ansell.propertyutil.PropertyUtil; import com.github.podd.api.PoddRepositoryManager; import com.github.podd.exception.RepositoryNotFoundException; import com.github.podd.utils.ManualShutdownRepository; import com.github.podd.utils.OntologyUtils; import com.github.podd.utils.PODD; /** * @author Peter Ansell p_ansell@yahoo.com * */ public class PoddRepositoryManagerImpl implements PoddRepositoryManager { private final Logger log = LoggerFactory.getLogger(this.getClass()); private URI artifactGraph; private URI dataRepositoryGraph; private URI schemaGraph; private URI repositoryGraph; private String defaultPermanentRepositoryServerUrl; private Path poddHomeDirectory; private ManualShutdownRepository managementRepository; private ConcurrentMap<Set<? extends OWLOntologyID>, ManualShutdownRepository> permanentRepositories = new ConcurrentHashMap<>(); private RepositoryImplConfig permanentRepositoryConfigForNew; private ConcurrentMap<URI, RepositoryManager> sesameRepositoryManagers = new ConcurrentHashMap<>(); /** * * @param managementRepository * @param permanentRepository * @throws RepositoryConfigException */ public PoddRepositoryManagerImpl(final Repository managementRepository, final RepositoryImplConfig permanentRepositoryConfigForNew, final String defaultPermanentRepositoryServerUrl, final Path poddHomeDirectory, final PropertyUtil props) throws RepositoryConfigException { this.managementRepository = new ManualShutdownRepository(managementRepository); // this.sesameRepositoryManager = repositoryManager; this.permanentRepositoryConfigForNew = permanentRepositoryConfigForNew; this.defaultPermanentRepositoryServerUrl = defaultPermanentRepositoryServerUrl; this.poddHomeDirectory = poddHomeDirectory; this.artifactGraph = PODD.VF.createURI(props.get(PODD.PROPERTY_ARTIFACT_MANAGEMENT_GRAPH, PODD.DEFAULT_ARTIFACT_MANAGEMENT_GRAPH.stringValue())); this.dataRepositoryGraph = PODD.VF.createURI(props.get(PODD.PROPERTY_DATA_REPOSITORY_MANAGEMENT_GRAPH, PODD.DEFAULT_DATA_REPOSITORY_MANAGEMENT_GRAPH.stringValue())); this.schemaGraph = PODD.VF.createURI(props.get(PODD.PROPERTY_SCHEMA_MANAGEMENT_GRAPH, PODD.DEFAULT_SCHEMA_MANAGEMENT_GRAPH.stringValue())); this.repositoryGraph = PODD.VF.createURI(props.get(PODD.PROPERTY_REPOSITORY_MANAGEMENT_GRAPH, PODD.DEFAULT_REPOSITORY_MANAGEMENT_GRAPH.stringValue())); } @Override public URI getArtifactManagementGraph() { return this.artifactGraph; } @Override public URI getFileRepositoryManagementGraph() { return this.dataRepositoryGraph; } @Override public RepositoryConnection getManagementRepositoryConnection() throws OpenRDFException { this.log.debug("Get management repository"); return this.managementRepository.getConnection(); } @Override public Repository getNewTemporaryRepository() throws OpenRDFException { this.log.debug("Started creating temporary MemoryStore repository"); final Repository result = new SailRepository(new MemoryStore()); result.initialize(); this.log.debug("Finished creating temporary MemoryStore repository"); return result; } @Override public RepositoryConnection getPermanentRepositoryConnection(final Set<? extends OWLOntologyID> schemaOntologies) throws OpenRDFException, IOException, RepositoryNotFoundException { return this.getPermanentRepositoryConnection(schemaOntologies, false); } @Override public RepositoryConnection getPermanentRepositoryConnection(final Set<? extends OWLOntologyID> schemaOntologies, final boolean createIfNotExists) throws OpenRDFException, IOException, RepositoryNotFoundException { this.log.debug("Entering get permanent repository: createIfNotExists={}", createIfNotExists); this.log.debug("Get permanent repository schemas: {}", schemaOntologies); Objects.requireNonNull(schemaOntologies, "Schema ontologies must not be null"); if(schemaOntologies.isEmpty()) { throw new IllegalArgumentException("Schema ontologies cannot be empty"); } if(this.log.isTraceEnabled()) { new RuntimeException().printStackTrace(); } ManualShutdownRepository permanentRepository = this.getPermanentRepositoryInternal(schemaOntologies); // ManualShutdownRepository permanentRepository = // this.permanentRepositories.get(schemaOntologies); // This synchronisation should not inhibit most operations, but is necessary to prevent // multiple repositories with the same schema ontologies, given that there is a relatively // large latency in the new repository create process // ConcurrentMap.putIfAbsent is not applicable to the initial situation as it is very costly // to create a repository if it is not needed if(permanentRepository == null) { synchronized(this.permanentRepositories) { permanentRepository = this.getPermanentRepositoryInternal(schemaOntologies); if(permanentRepository == null) { this.log.debug("Permanent repository not cached, but may exist"); RepositoryConnection managementConnection = null; try { managementConnection = this.getManagementRepositoryConnection(); managementConnection.begin(); URI repositoryUri = null; final Entry<Resource, RepositoryManager> sesameRepositoryManagerMap = this.getRepositoryManagerEntry(schemaOntologies, managementConnection); final Resource repositoryManagerURI = sesameRepositoryManagerMap.getKey(); final RepositoryManager sesameRepositoryManager = sesameRepositoryManagerMap.getValue(); final Model repositoriesInManagerModel = new LinkedHashModel(); managementConnection.exportStatements(repositoryManagerURI, PODD.PODD_REPOSITORY_MANAGER_CONTAINS_REPOSITORY, null, false, new StatementCollector( repositoriesInManagerModel), this.repositoryGraph); for(final Value nextRepository : repositoriesInManagerModel.objects()) { if(nextRepository instanceof URI) { final Model model = new LinkedHashModel(); managementConnection.exportStatements((URI)nextRepository, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_VERSION, null, true, new StatementCollector(model), this.repositoryGraph); final Set<Value> schemasInRepository = model.filter((URI)nextRepository, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_VERSION, null).objects(); boolean missingSchema = false; if(schemasInRepository.size() != schemaOntologies.size()) { continue; } for(final OWLOntologyID nextSchemaOntology : schemaOntologies) { if(!model.contains((URI)nextRepository, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_VERSION, nextSchemaOntology .getVersionIRI().toOpenRDFURI())) { missingSchema = true; break; } } for(final Value nextSchema : schemasInRepository) { if(nextSchema instanceof URI) { boolean foundNextSchema = false; for(final OWLOntologyID nextSchemaOntology : schemaOntologies) { if(nextSchemaOntology.getVersionIRI().toOpenRDFURI().equals(nextSchema)) { foundNextSchema = true; break; } } if(!foundNextSchema) { missingSchema = true; break; } } else { // If the schema was not a URI we have no hope of finding // it, so report it as missing missingSchema = true; } } if(!missingSchema) { repositoryUri = (URI)nextRepository; break; } } } // If no existing repository found, then create one, else we regenerate a // reference to the existing repository if(repositoryUri == null) { // Throw exception after debugging if we were told not to create a new // repository for this case if(!createIfNotExists) { if(this.log.isDebugEnabled()) { final Set<Value> debugRepositories = repositoriesInManagerModel.filter(null, RDF.TYPE, PODD.PODD_REPOSITORY, this.repositoryGraph).objects(); this.log.debug("Listing all {} repositories in manager:", debugRepositories.size()); for(final Value nextRepositoryUri : debugRepositories) { if(!(nextRepositoryUri instanceof URI)) { this.log.error("Found repository labelled with a non-URI: {}", nextRepositoryUri); continue; } this.log.debug("\t{}", nextRepositoryUri); final Set<Value> ontologiesInNextRepository = repositoriesInManagerModel.filter((URI)nextRepositoryUri, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_VERSION, null).objects(); for(final Value nextOntologyInNextRepository : ontologiesInNextRepository) { this.log.debug("\t\t{}", nextOntologyInNextRepository); } } } throw new RepositoryNotFoundException( "Could not find an existing repository for the given set of schema ontolgoies: " + schemaOntologies); } this.log.debug("Permanent repository not created yet"); // Create a new one repositoryUri = managementConnection.getValueFactory().createURI("urn:podd:repository:", UUID.randomUUID().toString()); // Get a new repository ID using our base name as the starting point final String newRepositoryID = sesameRepositoryManager.getNewRepositoryID(repositoryUri.stringValue()); final Date creationDate = new Date(); final SimpleDateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); final RepositoryConfig config = new RepositoryConfig(newRepositoryID, "PODD Redesign Repository (Automatically created at " + iso8601Format.format(creationDate) + ")", this.permanentRepositoryConfigForNew); sesameRepositoryManager.addRepositoryConfig(config); final ManualShutdownRepository nextRepository = new ManualShutdownRepository(this.getRepositoryByID(sesameRepositoryManager, newRepositoryID)); // If we somehow created a new repository since we entered this section, // we need to remove the new repository to cleanup final ManualShutdownRepository putIfAbsent = this.permanentRepositories.putIfAbsent(schemaOntologies, nextRepository); if(putIfAbsent != null) { this.log.error("Created a new duplicate repository that must now be removed: {}", newRepositoryID); final boolean removeRepository = sesameRepositoryManager.removeRepository(newRepositoryID); if(!removeRepository) { this.log.warn("Could not remove duplicate repository: {}", newRepositoryID); } permanentRepository = putIfAbsent; } else { this.log.debug("Permanent repository created: {}", newRepositoryID); permanentRepository = nextRepository; // In this case, we need to copy the relevant schema ontologies over // to the new repository this.initialisePermanentRepository(schemaOntologies, managementConnection, permanentRepository); this.addNewRepositoryID(schemaOntologies, managementConnection, repositoryUri, repositoryManagerURI, newRepositoryID); } } else { this.log.debug("Permanent repository exists but not cached: {}", repositoryUri); if(this.log.isTraceEnabled()) { new RuntimeException().printStackTrace(); } // create reference to existing repositoryUri final Model model = new LinkedHashModel(); managementConnection.exportStatements(repositoryUri, null, null, false, new StatementCollector(model), this.repositoryGraph); if(!model.contains(repositoryUri, RDF.TYPE, PODD.PODD_REPOSITORY)) { throw new RuntimeException( "Found repository that was not typed correctly in management graph: " + repositoryUri.stringValue()); } Repository nextRepository = null; try { final Literal existingRepositoryId = model.filter(repositoryUri, PODD.PODD_REPOSITORY_ID_IN_MANAGER, null) .objectLiteral(); nextRepository = sesameRepositoryManager.getRepository(existingRepositoryId.getLabel()); if(nextRepository == null) { throw new RuntimeException("Failed to get existing repository from manager: " + existingRepositoryId); } } catch(final ModelException e) { throw new RuntimeException("Failed to find a unique repositoryId in manager", e); } // Wrap the repository so that it will not be accidentally shutdown by // user code outside of our lifecycle here nextRepository = new ManualShutdownRepository(nextRepository); final ManualShutdownRepository putIfAbsent = this.permanentRepositories.putIfAbsent(schemaOntologies, (ManualShutdownRepository)nextRepository); if(putIfAbsent != null) { // TODO: Should we shutdown the repository that is being replaced? // Ideally we will be shutting down the repository manager later, // and they should be references to the same Repository anyway // nextRepository.shutDown(); nextRepository = putIfAbsent; } permanentRepository = (ManualShutdownRepository)nextRepository; } managementConnection.commit(); } catch(final Throwable e) { if(managementConnection != null) { managementConnection.rollback(); } throw e; } finally { if(managementConnection != null) { managementConnection.close(); } } } } } this.log.debug("Returning from get permanent repository"); return permanentRepository.getConnection(); } /** * @param schemaOntologies * @param managementConnection * @return * @throws RepositoryException * @throws RDFHandlerException * @throws IOException */ protected Entry<Resource, RepositoryManager> getRepositoryManagerEntry( final Set<? extends OWLOntologyID> schemaOntologies, final RepositoryConnection managementConnection) throws RepositoryException, RDFHandlerException, IOException { final Map<Resource, RepositoryManager> sesameRepositoryManagerMap = this.getRepositoryManager(schemaOntologies, managementConnection, this.repositoryGraph); if(sesameRepositoryManagerMap.isEmpty()) { throw new RuntimeException("Could not create repository manager"); } if(sesameRepositoryManagerMap.size() > 1) { throw new RuntimeException( "Found duplicate repository managers for the same set of schema ontologies. Failing fast to avoid further data corruption. " + schemaOntologies.toString()); } return sesameRepositoryManagerMap.entrySet().iterator().next(); } /** * Initialise the given permanent repository with the given schema ontologies, which have * already been loaded into the management repository that has a {@link RepositoryConnection} * open already. * * @param schemaOntologies * @param managementConnection * @param permanentRepository * @throws RepositoryException */ protected void initialisePermanentRepository(final Set<? extends OWLOntologyID> schemaOntologies, final RepositoryConnection managementConnection, final Repository permanentRepository) throws RepositoryException { final RepositoryConnection permanentConnection = permanentRepository.getConnection(); try { permanentConnection.begin(); for(final OWLOntologyID nextSchemaOntology : schemaOntologies) { if(nextSchemaOntology.getVersionIRI() != null) { if(!managementConnection.hasStatement(null, null, null, false, nextSchemaOntology.getVersionIRI() .toOpenRDFURI())) { throw new RepositoryException("Management repository did not contain a schema ontology: " + nextSchemaOntology); } if(!permanentConnection.hasStatement(null, null, null, false, nextSchemaOntology.getVersionIRI() .toOpenRDFURI())) { permanentConnection.add(managementConnection.getStatements(null, null, null, false, nextSchemaOntology.getVersionIRI().toOpenRDFURI()), nextSchemaOntology.getVersionIRI() .toOpenRDFURI()); } final RepositoryResult<Statement> statements = managementConnection.getStatements(nextSchemaOntology.getVersionIRI().toOpenRDFURI(), PODD.PODD_BASE_INFERRED_VERSION, null, false, this.getSchemaManagementGraph()); for(final Statement nextInferredStatement : Iterations.asList(statements)) { if(nextInferredStatement.getObject() instanceof URI) { if(!permanentConnection.hasStatement(null, null, null, false, (URI)nextInferredStatement.getObject())) { permanentConnection .add(managementConnection.getStatements(null, null, null, false, (URI)nextInferredStatement.getObject()), (URI)nextInferredStatement .getObject()); } } } } } permanentConnection.commit(); } catch(final Throwable e) { if(permanentConnection != null) { permanentConnection.rollback(); } throw e; } finally { if(permanentConnection != null) { permanentConnection.close(); } } } protected void addNewRepositoryID(final Set<? extends OWLOntologyID> schemaOntologies, final RepositoryConnection managementConnection, final URI repositoryUri, final Resource repositoryManagerURI, final String newRepositoryID) throws RepositoryException { final Literal repositoryIdInManager = managementConnection.getValueFactory().createLiteral(newRepositoryID); managementConnection.add(repositoryManagerURI, PODD.PODD_REPOSITORY_MANAGER_CONTAINS_REPOSITORY, repositoryUri, this.repositoryGraph); managementConnection.add(repositoryUri, RDF.TYPE, PODD.PODD_REPOSITORY, this.repositoryGraph); managementConnection.add(repositoryUri, PODD.PODD_REPOSITORY_ID_IN_MANAGER, repositoryIdInManager, this.repositoryGraph); for(final OWLOntologyID nextSchemaOntologyID : schemaOntologies) { managementConnection.add(repositoryUri, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_IRI, nextSchemaOntologyID .getOntologyIRI().toOpenRDFURI(), this.repositoryGraph); managementConnection.add(repositoryUri, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_VERSION, nextSchemaOntologyID .getVersionIRI().toOpenRDFURI(), this.repositoryGraph); } } protected Repository getRepositoryByID(final RepositoryManager sesameRepositoryManager, final String newRepositoryID) throws RepositoryConfigException, RepositoryException { return sesameRepositoryManager.getRepository(newRepositoryID); } protected ManualShutdownRepository getPermanentRepositoryInternal( final Set<? extends OWLOntologyID> schemaOntologies) { for(final Entry<Set<? extends OWLOntologyID>, ManualShutdownRepository> nextEntry : this.permanentRepositories .entrySet()) { if(OntologyUtils.ontologyVersionsMatch(schemaOntologies, nextEntry.getKey())) { return nextEntry.getValue(); } } return null; } @Override public URI getSchemaManagementGraph() { return this.schemaGraph; } @Override public boolean safeContexts(final URI... contexts) { boolean returnValue = true; if(contexts == null) { returnValue = false; } else if(contexts.length == 0) { returnValue = false; } else { for(final URI nextContext : contexts) { if(nextContext == null) { returnValue = false; } else if(nextContext.equals(SESAME.NIL)) { returnValue = false; } else if(nextContext.equals(this.getArtifactManagementGraph())) { returnValue = false; } else if(nextContext.equals(this.getSchemaManagementGraph())) { returnValue = false; } else if(nextContext.equals(this.getFileRepositoryManagementGraph())) { returnValue = false; } else if(nextContext.equals(this.repositoryGraph)) { returnValue = false; } } } if(!returnValue) { this.log.warn("Found unsafe URI contexts: <{}>", Arrays.asList(contexts)); } return returnValue; } @Override public void setArtifactManagementGraph(final URI artifactManagementGraph) { this.artifactGraph = artifactManagementGraph; } @Override public void setFileRepositoryManagementGraph(final URI dataRepositoryManagementGraph) { this.dataRepositoryGraph = dataRepositoryManagementGraph; } @Override public void setManagementRepository(final Repository repository) throws OpenRDFException { this.managementRepository = new ManualShutdownRepository(repository); } @Override public void setSchemaManagementGraph(final URI schemaManagementGraph) { this.schemaGraph = schemaManagementGraph; } @Override public void shutDown() throws RepositoryException { RepositoryException foundException = null; try { if(this.managementRepository != null) { this.log.debug("Shutting down management repository"); this.managementRepository.realShutDown(); } } catch(final RepositoryException e) { this.log.error("Found exception shutting down management repository", e); foundException = e; } finally { synchronized(this.permanentRepositories) { for(final Entry<Set<? extends OWLOntologyID>, ManualShutdownRepository> nextRepository : this.permanentRepositories .entrySet()) { try { this.log.debug("Shutting down repository for schema ontologies: {} ", nextRepository.getKey()); nextRepository.getValue().realShutDown(); } catch(final RepositoryException e) { this.log.error("Found exception shutting down permanent repository for schema ontologies: " + nextRepository.getKey(), e); if(foundException == null) { foundException = e; } else { foundException.addSuppressed(e); } } } this.permanentRepositories.clear(); } synchronized(this.sesameRepositoryManagers) { for(final Entry<URI, RepositoryManager> nextManager : this.sesameRepositoryManagers.entrySet()) { try { this.log.debug("Shutting down repository manager: {} ", nextManager.getKey()); nextManager.getValue().shutDown(); } catch(final RuntimeException e) { this.log.error("Found exception shutting down repository manager: " + nextManager.getKey(), e); if(foundException == null) { foundException = new RepositoryException("Could not shutdown a repository manager", e); } else { foundException.addSuppressed(e); } } } this.sesameRepositoryManagers.clear(); } } this.managementRepository = null; if(foundException != null) { throw foundException; } } @Override public Repository getReadOnlyFederatedRepository(final Set<? extends OWLOntologyID> schemaImports) throws OpenRDFException, IOException { final Federation federation = new Federation(); federation.setReadOnly(true); // FIXME: Need an internal method that returns a repository to support this // federation.addMember(this.getPermanentRepositoryConnection(schemaImports)); // federation.addMember(this.getManagementRepositoryConnection()); federation.initialize(); final Repository federationRepository = new SailRepository(federation); federationRepository.initialize(); return federationRepository; } protected Map<Resource, RepositoryManager> getRepositoryManager(final Set<? extends OWLOntologyID> schemaImports, final RepositoryConnection managementConnection, final URI repositoryManagementContext) throws RepositoryException, RDFHandlerException, IOException { final Model model = new LinkedHashModel(); managementConnection.export(new StatementCollector(model), repositoryManagementContext); for(final Resource nextRepositoryManager : model.filter(null, RDF.TYPE, PODD.PODD_REPOSITORY_MANAGER) .subjects()) { if(nextRepositoryManager instanceof URI) { final Set<Value> repositories = model.filter(nextRepositoryManager, PODD.PODD_REPOSITORY_MANAGER_CONTAINS_REPOSITORY, null) .objects(); for(final Value nextRepository : repositories) { if(nextRepository instanceof URI) { final Model schemas = model.filter((URI)nextRepository, PODD.PODD_REPOSITORY_CONTAINS_SCHEMA_VERSION, null); boolean allMatched = true; // Check that all of the schemas supported by this repository are in the // requested list of schema imports for(final Value nextSchema : schemas.objects()) { if(nextSchema instanceof URI) { boolean found = false; for(final OWLOntologyID nextSchemaImport : schemaImports) { if(nextSchemaImport.getVersionIRI().toOpenRDFURI().equals(nextSchema)) { found = true; break; } } if(!found) { allMatched = false; break; } } } // Check also that all of the requested schema imports are in the repository // Need to perform this check to ensure that there is an exact match // If there is not an exact match, and OWL database may not produce the // correct // set of inferences for(final OWLOntologyID nextSchemaImport : schemaImports) { boolean found = false; for(final Value nextSchema : schemas.objects()) { if(nextSchema instanceof URI) { if(nextSchemaImport.getVersionIRI().toOpenRDFURI().equals(nextSchema)) { found = true; break; } } } if(!found) { allMatched = false; break; } } if(allMatched) { RepositoryManager repositoryManager = this.sesameRepositoryManagers.get(nextRepositoryManager); if(repositoryManager != null) { return Collections.singletonMap(nextRepositoryManager, repositoryManager); } else { synchronized(this.sesameRepositoryManagers) { repositoryManager = this.sesameRepositoryManagers.get(nextRepositoryManager); if(repositoryManager != null) { return Collections.singletonMap(nextRepositoryManager, repositoryManager); } else { final URI repositoryManagerType = model.filter(nextRepositoryManager, PODD.PODD_REPOSITORY_MANAGER_TYPE, null).objectURI(); if(repositoryManagerType.equals(PODD.PODD_REPOSITORY_MANAGER_TYPE_LOCAL)) { final Literal directory = model.filter(nextRepositoryManager, PODD.PODD_REPOSITORY_MANAGER_LOCAL_DIRECTORY, null) .objectLiteral(); if(directory != null) { RepositoryManager localRepositoryManager = new LocalRepositoryManager(Paths.get(directory.stringValue()) .toFile()); localRepositoryManager.initialize(); final RepositoryManager putIfAbsent = this.sesameRepositoryManagers.putIfAbsent( (URI)nextRepositoryManager, localRepositoryManager); if(putIfAbsent != null) { localRepositoryManager.shutDown(); localRepositoryManager = putIfAbsent; } return Collections.<Resource, RepositoryManager> singletonMap( nextRepositoryManager, localRepositoryManager); } else { final Path path = Files.createTempDirectory("podd-temp-repositories-"); this.log.warn("Temporary local repositories in use!!!: {} {}", path.toString(), schemaImports); RepositoryManager localRepositoryManager = new LocalRepositoryManager(path.toFile()); localRepositoryManager.initialize(); final RepositoryManager putIfAbsent = this.sesameRepositoryManagers.putIfAbsent( (URI)nextRepositoryManager, localRepositoryManager); if(putIfAbsent != null) { localRepositoryManager.shutDown(); localRepositoryManager = putIfAbsent; } return Collections.<Resource, RepositoryManager> singletonMap( nextRepositoryManager, localRepositoryManager); } } else if(repositoryManagerType.equals(PODD.PODD_REPOSITORY_MANAGER_TYPE_REMOTE)) { final Literal serverURL = model.filter(nextRepositoryManager, PODD.PODD_REPOSITORY_MANAGER_REMOTE_SERVER_URL, null) .objectLiteral(); RepositoryManager remoteRepositoryManager = new RemoteRepositoryManager(serverURL.stringValue()); remoteRepositoryManager.initialize(); final RepositoryManager putIfAbsent = this.sesameRepositoryManagers.putIfAbsent( (URI)nextRepositoryManager, remoteRepositoryManager); if(putIfAbsent != null) { remoteRepositoryManager.shutDown(); remoteRepositoryManager = putIfAbsent; } return Collections.<Resource, RepositoryManager> singletonMap( nextRepositoryManager, remoteRepositoryManager); } else { throw new RuntimeException("Did not recognise repository manager type: " + repositoryManagerType.stringValue()); } } } } } } } } } // None were found so create a new repository manager based on configuration synchronized(this.sesameRepositoryManagers) { RepositoryManager repositoryManager = null; final Resource newRepositoryManagerURI = managementConnection.getValueFactory().createURI( "urn:podd:repositorymanager:" + UUID.randomUUID().toString()); managementConnection.add(newRepositoryManagerURI, RDF.TYPE, PODD.PODD_REPOSITORY_MANAGER, repositoryManagementContext); // We decide whether we will create a remote or a local repository manager based on the // default permanent repository server URL final String repositoryManagerUrl = this.defaultPermanentRepositoryServerUrl; if(repositoryManagerUrl == null || repositoryManagerUrl.trim().isEmpty()) { final Path nextPath = this.poddHomeDirectory.resolve(newRepositoryManagerURI.stringValue()); if(!Files.exists(nextPath, LinkOption.NOFOLLOW_LINKS)) { Files.createDirectories(nextPath); } repositoryManager = new LocalRepositoryManager(nextPath.toFile()); repositoryManager.initialize(); final Literal nextLiteral = managementConnection.getValueFactory().createLiteral(nextPath.toString()); managementConnection.add(newRepositoryManagerURI, PODD.PODD_REPOSITORY_MANAGER_TYPE, PODD.PODD_REPOSITORY_MANAGER_TYPE_LOCAL, repositoryManagementContext); managementConnection.add(newRepositoryManagerURI, PODD.PODD_REPOSITORY_MANAGER_LOCAL_DIRECTORY, nextLiteral, repositoryManagementContext); } else { repositoryManager = new RemoteRepositoryManager(repositoryManagerUrl); repositoryManager.initialize(); final Literal nextUrl = managementConnection.getValueFactory().createLiteral(repositoryManagerUrl); managementConnection.add(newRepositoryManagerURI, PODD.PODD_REPOSITORY_MANAGER_TYPE, PODD.PODD_REPOSITORY_MANAGER_TYPE_REMOTE, repositoryManagementContext); managementConnection.add(newRepositoryManagerURI, PODD.PODD_REPOSITORY_MANAGER_REMOTE_SERVER_URL, nextUrl, repositoryManagementContext); } final RepositoryManager putIfAbsent = this.sesameRepositoryManagers.putIfAbsent((URI)newRepositoryManagerURI, repositoryManager); if(putIfAbsent != null) { repositoryManager.shutDown(); repositoryManager = putIfAbsent; } return Collections.<Resource, RepositoryManager> singletonMap(newRepositoryManagerURI, repositoryManager); } } }