@Override public void initialize(ServletContext servletContext) { String contentPrimaryTypes = getParam(servletContext, INIT_CONTENT_PRIMARY_TYPE_NAMES); String resourcePrimaryTypes = getParam(servletContext, INIT_RESOURCE_PRIMARY_TYPES_NAMES); String newFolderPrimaryType = getParam(servletContext, INIT_NEW_FOLDER_PRIMARY_TYPE_NAME); String newResourcePrimaryType = getParam(servletContext, INIT_NEW_RESOURCE_PRIMARY_TYPE_NAME); String newContentPrimaryType = getParam(servletContext, INIT_NEW_CONTENT_PRIMARY_TYPE_NAME); logger.debug("DefaultContentMapper initial content primary types = " + contentPrimaryTypes); logger.debug("DefaultContentMapper initial file primary types = " + filePrimaryTypes); logger.debug("DefaultContentMapper initial new folder primary types = " + newFolderPrimaryType); logger.debug( "DefaultContentMapper initial new resource primary types = " + newResourcePrimaryType); logger.debug( "DefaultContentMapper initial new content primary types = " + newContentPrimaryType); this.contentPrimaryTypes = split(contentPrimaryTypes != null ? contentPrimaryTypes : DEFAULT_CONTENT_PRIMARY_TYPES); this.filePrimaryTypes = split(resourcePrimaryTypes != null ? resourcePrimaryTypes : DEFAULT_RESOURCE_PRIMARY_TYPES); this.newFolderPrimaryType = newFolderPrimaryType != null ? newFolderPrimaryType : DEFAULT_NEW_FOLDER_PRIMARY_TYPE; this.newResourcePrimaryType = newResourcePrimaryType != null ? newResourcePrimaryType : DEFAULT_NEW_RESOURCE_PRIMARY_TYPE; this.newContentPrimaryType = newContentPrimaryType != null ? newContentPrimaryType : DEFAULT_NEW_CONTENT_PRIMARY_TYPE; }
/** * Pings a connector by name. * * @param connectorName * @return RepositorySource - may be <code>null</code>) */ @ManagementOperation(description = "Pings a connector by name", impact = Impact.ReadOnly) public boolean pingConnector(String connectorName) { if (!isRunning()) return false; // Get engine to use for the rest of the method (this is synchronized) // ... final JcrEngine engine = getEngine(); assert engine != null; boolean success = false; String pingDuration = null; try { RepositoryConnectionPool pool = engine.getRepositoryService().getRepositoryLibrary().getConnectionPool(connectorName); if (pool != null) { Stopwatch sw = new Stopwatch(); sw.start(); success = pool.ping(); sw.stop(); pingDuration = sw.getTotalDuration().toString(); } } catch (Exception e) { Logger.getLogger(getClass()) .error(e, JBossManagedI18n.errorDeterminingIfConnectionIsAlive, connectorName); } if (pingDuration == null) pingDuration = new Duration(0L).toString(); return success; }
/** * Get the number of connections currently in use * * @param connectorName * @return boolean */ @ManagementOperation( description = "Get the number of connections currently in use", impact = Impact.ReadOnly) public long getInUseConnections(String connectorName) { if (!isRunning()) return 0; // Get engine to use for the rest of the method (this is synchronized) final JcrEngine engine = getEngine(); assert engine != null; long totalConnectionsInUse = 0; try { totalConnectionsInUse = engine .getRepositoryService() .getRepositoryLibrary() .getConnectionPool(connectorName) .getInUseCount(); } catch (Exception e) { Logger.getLogger(getClass()) .error(e, JBossManagedI18n.errorDeterminingTotalInUseConnections, connectorName); } return totalConnectionsInUse; }
protected void process(Changes changes) { try { searchEngine.index(context, changes.getChangeRequests()); } catch (RuntimeException e) { Logger.getLogger(getClass()) .error(e, JcrI18n.errorUpdatingQueryIndexes, e.getLocalizedMessage()); } }
/** * Obtains the specified managed repository of this engine. This is called by the * JNDIManagedRepositories when a JNDI lookup is performed to find a repository. * * @param repositoryName for the repository to be returned * @return a repository or <code>null</code> if repository doesn't exist */ public JcrRepository getRepository(String repositoryName) { if (!isRunning()) return null; // Get engine to use for the rest of the method (this is synchronized) // ... final JcrEngine engine = getEngine(); assert engine != null; try { return engine.getRepository(repositoryName); } catch (RepositoryException e) { Logger.getLogger(getClass()) .error(e, JBossManagedI18n.errorGettingRepositoryFromEngine, repositoryName); return null; } }
/** * Refresh the node types from the stored representation. * * @return true if there was at least one node type found, or false if there were none */ protected boolean refreshFromSystem() { Lock lock = this.namespacesLock.writeLock(); try { lock.lock(); // Re-read and re-register all of the namespaces ... SessionCache systemCache = repository.createSystemSession(context, false); SystemContent system = new SystemContent(systemCache); Collection<Namespace> namespaces = system.readAllNamespaces(); if (namespaces.isEmpty()) return false; this.cache.clear(); this.cache.register(namespaces); } catch (Throwable e) { logger.error(e, JcrI18n.errorRefreshingNodeTypes, repository.name()); } finally { lock.unlock(); } return true; }
/** * Get the number of sessions currently active * * @param repositoryName * @return boolean */ @ManagementOperation( description = "Get the number of sessions currently active", impact = Impact.ReadOnly) public long getActiveSessions(String repositoryName) { if (!isRunning()) return 0; // Get engine to use for the rest of the method (this is synchronized) final JcrEngine engine = getEngine(); assert engine != null; int totalActiveSessions = 0; try { totalActiveSessions = getRepository(repositoryName).getMetrics().getActiveSessionCount(); } catch (Exception e) { Logger.getLogger(getClass()) .error(e, JBossManagedI18n.errorDeterminingTotalInUseConnections, repositoryName); } return totalActiveSessions; }
/** * A {@link NamespaceRegistry} implementation that stores the namespaces in the '/jcr:system' area * as individual nodes for each namespace. */ @ThreadSafe public class SystemNamespaceRegistry implements NamespaceRegistry { public static final Name URI_PROPERTY_NAME = ModeShapeLexicon.URI; public static final Name GENERATED_PROPERTY_NAME = ModeShapeLexicon.GENERATED; private final JcrRepository.RunningState repository; private final SimpleNamespaceRegistry cache; private ExecutionContext context; private final ReadWriteLock namespacesLock = new ReentrantReadWriteLock(); private final Logger logger = Logger.getLogger(getClass()); SystemNamespaceRegistry(JcrRepository.RunningState repository) { this.repository = repository; this.cache = new SimpleNamespaceRegistry(); // Pre-load all of the built-in namespaces ... this.cache.register(new ExecutionContext().getNamespaceRegistry().getNamespaces()); } void setContext(ExecutionContext context) { this.context = context; } /** * Refresh the node types from the stored representation. * * @return true if there was at least one node type found, or false if there were none */ protected boolean refreshFromSystem() { Lock lock = this.namespacesLock.writeLock(); try { lock.lock(); // Re-read and re-register all of the namespaces ... SessionCache systemCache = repository.createSystemSession(context, false); SystemContent system = new SystemContent(systemCache); Collection<Namespace> namespaces = system.readAllNamespaces(); if (namespaces.isEmpty()) return false; this.cache.clear(); this.cache.register(namespaces); } catch (Throwable e) { logger.error(e, JcrI18n.errorRefreshingNodeTypes, repository.name()); } finally { lock.unlock(); } return true; } private final SystemContent systemContent(boolean readOnly) { SessionCache systemCache = repository.createSystemSession(context, readOnly); return new SystemContent(systemCache); } @Override public String getNamespaceForPrefix(String prefix) { Lock lock = this.namespacesLock.readLock(); try { lock.lock(); CheckArg.isNotNull(prefix, "prefix"); return cache.getNamespaceForPrefix(prefix); } finally { lock.unlock(); } } @Override public String getPrefixForNamespaceUri(String namespaceUri, boolean generateIfMissing) { CheckArg.isNotNull(namespaceUri, "namespaceUri"); Lock lock = this.namespacesLock.readLock(); try { lock.lock(); // Try the cache first ... String prefix = cache.getPrefixForNamespaceUri(namespaceUri, false); if (prefix == null && generateIfMissing) { SystemContent systemContent = systemContent(!generateIfMissing); prefix = systemContent.readNamespacePrefix(namespaceUri, generateIfMissing); if (prefix != null) { systemContent.save(); cache.register(prefix, namespaceUri); } } return prefix; } finally { lock.unlock(); } } @Override public boolean isRegisteredNamespaceUri(String namespaceUri) { CheckArg.isNotNull(namespaceUri, "namespaceUri"); Lock lock = this.namespacesLock.readLock(); try { lock.lock(); return cache.isRegisteredNamespaceUri(namespaceUri); } finally { lock.unlock(); } } @Override public String getDefaultNamespaceUri() { return this.getNamespaceForPrefix(""); } @Override public void register(Iterable<Namespace> namespaces) { final Lock lock = this.namespacesLock.writeLock(); try { lock.lock(); Map<String, String> urisByPrefix = new HashMap<String, String>(); for (Namespace namespace : namespaces) { urisByPrefix.put(namespace.getPrefix(), namespace.getNamespaceUri()); } register(urisByPrefix); } finally { lock.unlock(); } } /** * Register a set of namespaces. * * @param namespaceUrisByPrefix the map of new namespace URIs by their prefix */ public void register(Map<String, String> namespaceUrisByPrefix) { if (namespaceUrisByPrefix == null || namespaceUrisByPrefix.isEmpty()) return; final Lock lock = this.namespacesLock.writeLock(); try { lock.lock(); SystemContent systemContent = systemContent(false); systemContent.registerNamespaces(namespaceUrisByPrefix); systemContent.save(); for (Map.Entry<String, String> entry : namespaceUrisByPrefix.entrySet()) { String prefix = entry.getKey().trim(); String uri = entry.getValue().trim(); if (prefix.length() == 0) continue; this.cache.register(prefix, uri); } } finally { lock.unlock(); } } @Override public String register(String prefix, String namespaceUri) { CheckArg.isNotNull(namespaceUri, "namespaceUri"); namespaceUri = namespaceUri.trim(); final Lock lock = this.namespacesLock.writeLock(); try { lock.lock(); // Register it in the cache first ... String previousCachedUriForPrefix = this.cache.register(prefix, namespaceUri); if (!namespaceUri.equals(previousCachedUriForPrefix)) { // And register it in the source ... SystemContent systemContent = systemContent(false); systemContent.registerNamespaces(Collections.singletonMap(prefix, namespaceUri)); systemContent.save(); } return previousCachedUriForPrefix; } finally { lock.unlock(); } } @Override public boolean unregister(String namespaceUri) { CheckArg.isNotNull(namespaceUri, "namespaceUri"); namespaceUri = namespaceUri.trim(); final Lock lock = this.namespacesLock.writeLock(); try { lock.lock(); // Remove it from the cache ... boolean found = this.cache.unregister(namespaceUri); // Then from the source ... SystemContent systemContent = systemContent(false); boolean foundPersistent = systemContent.unregisterNamespace(namespaceUri); systemContent.save(); return foundPersistent || found; } finally { lock.unlock(); } } @Override public Set<String> getRegisteredNamespaceUris() { final Lock lock = this.namespacesLock.readLock(); try { lock.lock(); // Just return what's in the cache ... return cache.getRegisteredNamespaceUris(); } finally { lock.unlock(); } } @Override public Set<Namespace> getNamespaces() { final Lock lock = this.namespacesLock.readLock(); try { lock.lock(); // Just return what's in the cache ... return cache.getNamespaces(); } finally { lock.unlock(); } } /** * {@inheritDoc} * * @see java.lang.Object#toString() */ @Override public String toString() { List<Namespace> namespaces = new ArrayList<Namespace>(getNamespaces()); Collections.sort(namespaces); return namespaces.toString(); } }
public class DefaultContentMapper implements ContentMapper { public static final String INIT_CONTENT_PRIMARY_TYPE_NAMES = "org.modeshape.web.jcr.webdav.CONTENT_PRIMARY_TYPE_NAMES"; public static final String INIT_RESOURCE_PRIMARY_TYPES_NAMES = "org.modeshape.web.jcr.webdav.RESOURCE_PRIMARY_TYPE_NAMES"; public static final String INIT_NEW_FOLDER_PRIMARY_TYPE_NAME = "org.modeshape.web.jcr.webdav.NEW_FOLDER_PRIMARY_TYPE_NAME"; public static final String INIT_NEW_RESOURCE_PRIMARY_TYPE_NAME = "org.modeshape.web.jcr.webdav.NEW_RESOURCE_PRIMARY_TYPE_NAME"; public static final String INIT_NEW_CONTENT_PRIMARY_TYPE_NAME = "org.modeshape.web.jcr.webdav.NEW_CONTENT_PRIMARY_TYPE_NAME"; private static final String CONTENT_NODE_NAME = "jcr:content"; private static final String DATA_PROP_NAME = "jcr:data"; private static final String MODIFIED_PROP_NAME = "jcr:lastModified"; private static final String ENCODING_PROP_NAME = "jcr:encoding"; private static final String MIME_TYPE_PROP_NAME = "jcr:mimeType"; private static final String DEFAULT_CONTENT_PRIMARY_TYPES = "nt:resource, mode:resource"; private static final String DEFAULT_RESOURCE_PRIMARY_TYPES = "nt:file"; private static final String DEFAULT_NEW_FOLDER_PRIMARY_TYPE = "nt:folder"; private static final String DEFAULT_NEW_RESOURCE_PRIMARY_TYPE = "nt:file"; private static final String DEFAULT_NEW_CONTENT_PRIMARY_TYPE = "nt:resource"; private Collection<String> contentPrimaryTypes; private Collection<String> filePrimaryTypes; private String newFolderPrimaryType; private String newResourcePrimaryType; private String newContentPrimaryType; private MimeTypeDetector mimeTypeDetector = new ApertureMimeTypeDetector(); private final Logger logger = Logger.getLogger(getClass()); @Override public void initialize(ServletContext servletContext) { String contentPrimaryTypes = getParam(servletContext, INIT_CONTENT_PRIMARY_TYPE_NAMES); String resourcePrimaryTypes = getParam(servletContext, INIT_RESOURCE_PRIMARY_TYPES_NAMES); String newFolderPrimaryType = getParam(servletContext, INIT_NEW_FOLDER_PRIMARY_TYPE_NAME); String newResourcePrimaryType = getParam(servletContext, INIT_NEW_RESOURCE_PRIMARY_TYPE_NAME); String newContentPrimaryType = getParam(servletContext, INIT_NEW_CONTENT_PRIMARY_TYPE_NAME); logger.debug("DefaultContentMapper initial content primary types = " + contentPrimaryTypes); logger.debug("DefaultContentMapper initial file primary types = " + filePrimaryTypes); logger.debug("DefaultContentMapper initial new folder primary types = " + newFolderPrimaryType); logger.debug( "DefaultContentMapper initial new resource primary types = " + newResourcePrimaryType); logger.debug( "DefaultContentMapper initial new content primary types = " + newContentPrimaryType); this.contentPrimaryTypes = split(contentPrimaryTypes != null ? contentPrimaryTypes : DEFAULT_CONTENT_PRIMARY_TYPES); this.filePrimaryTypes = split(resourcePrimaryTypes != null ? resourcePrimaryTypes : DEFAULT_RESOURCE_PRIMARY_TYPES); this.newFolderPrimaryType = newFolderPrimaryType != null ? newFolderPrimaryType : DEFAULT_NEW_FOLDER_PRIMARY_TYPE; this.newResourcePrimaryType = newResourcePrimaryType != null ? newResourcePrimaryType : DEFAULT_NEW_RESOURCE_PRIMARY_TYPE; this.newContentPrimaryType = newContentPrimaryType != null ? newContentPrimaryType : DEFAULT_NEW_CONTENT_PRIMARY_TYPE; } protected String getParam(ServletContext servletContext, String name) { return servletContext.getInitParameter(name); } /** * Returns an unmodifiable set containing the elements passed in to this method * * @param elements a set of elements; may not be null * @return an unmodifiable set containing all of the elements in {@code elements}; never null */ private static final Set<String> setFor(String... elements) { Set<String> set = new HashSet<String>(elements.length); set.addAll(Arrays.asList(elements)); return set; } /** * Splits a comma-delimited string into an unmodifiable set containing the substrings between the * commas in the source string. The elements in the set will be {@link String#trim() trimmed}. * * @param commaDelimitedString input string; may not be null, but need not contain any commas * @return an unmodifiable set whose elements are the trimmed substrings of the source string; * never null */ private static final Set<String> split(String commaDelimitedString) { return setFor(commaDelimitedString.split("\\s*,\\s*")); } @Override public InputStream getResourceContent(Node node) throws RepositoryException { if (!node.hasNode(CONTENT_NODE_NAME)) return null; return node.getProperty(CONTENT_NODE_NAME + "/" + DATA_PROP_NAME).getBinary().getStream(); } @Override public long getResourceLength(Node node) throws RepositoryException, IOException { InputStream is = getResourceContent(node); long size = 0; int bytesRead; byte[] buff = new byte[255]; while (-1 != (bytesRead = is.read(buff, 0, 255))) { size += bytesRead; } return size; } @Override public Date getLastModified(Node node) throws RepositoryException { if (!node.hasNode(CONTENT_NODE_NAME)) return null; return node.getProperty(CONTENT_NODE_NAME + "/" + MODIFIED_PROP_NAME).getDate().getTime(); } @Override public boolean isFolder(Node node) throws RepositoryException { return !isFile(node) && !isContent(node); } /** * @param node the node to check * @return true if {@code node}'s primary type is one of the types in {@link #filePrimaryTypes}; * may not be null * @throws RepositoryException if an error occurs checking the node's primary type */ @Override public boolean isFile(Node node) throws RepositoryException { for (String nodeType : filePrimaryTypes) { if (node.isNodeType(nodeType)) return true; } return false; } /** * @param node the node to check * @return true if {@code node}'s primary type is one of the types in {@link * #contentPrimaryTypes}; may not be null * @throws RepositoryException if an error occurs checking the node's primary type */ private boolean isContent(Node node) throws RepositoryException { for (String nodeType : contentPrimaryTypes) { if (node.isNodeType(nodeType)) return true; } return false; } @Override public void createFile(Node parentNode, String fileName) throws RepositoryException { Node resourceNode = parentNode.addNode(fileName, newResourcePrimaryType); Node contentNode = resourceNode.addNode(CONTENT_NODE_NAME, newContentPrimaryType); contentNode.setProperty(DATA_PROP_NAME, ""); contentNode.setProperty(MODIFIED_PROP_NAME, Calendar.getInstance()); contentNode.setProperty(ENCODING_PROP_NAME, "UTF-8"); contentNode.setProperty(MIME_TYPE_PROP_NAME, "text/plain"); } @Override public void createFolder(Node parentNode, String folderName) throws RepositoryException { parentNode.addNode(folderName, newFolderPrimaryType); } @Override public long setContent( Node parentNode, String resourceName, InputStream newContent, String contentType, String characterEncoding) throws RepositoryException, IOException { Node contentNode; if (parentNode.hasNode(CONTENT_NODE_NAME)) { contentNode = parentNode.getNode(CONTENT_NODE_NAME); } else { contentNode = parentNode.addNode(CONTENT_NODE_NAME, newContentPrimaryType); } // contentNode.setProperty(MIME_TYPE_PROP_NAME, contentType != null ? contentType : // "application/octet-stream"); contentNode.setProperty( ENCODING_PROP_NAME, characterEncoding != null ? characterEncoding : "UTF-8"); Binary binary = parentNode.getSession().getValueFactory().createBinary(newContent); contentNode.setProperty(DATA_PROP_NAME, binary); contentNode.setProperty(MODIFIED_PROP_NAME, Calendar.getInstance()); // Copy the content to the property, THEN re-read the content from the Binary value to avoid // discaring the first // bytes of the stream if (contentType == null) { contentType = mimeTypeDetector.mimeTypeOf(resourceName, binary.getStream()); } return contentNode.getProperty(DATA_PROP_NAME).getLength(); } }
/** * The basic component that encapsulates the ModeShape services, including the {@link Repository} * instances. */ @ThreadSafe public class JcrEngine extends ModeShapeEngine implements Repositories { static final int LOCK_SWEEP_INTERVAL_IN_MILLIS = 30000; static final int LOCK_EXTENSION_INTERVAL_IN_MILLIS = LOCK_SWEEP_INTERVAL_IN_MILLIS * 2; private static final Logger log = Logger.getLogger(ModeShapeEngine.class); private final Map<String, JcrRepositoryHolder> repositories; private final Lock repositoriesLock; private final Map<String, Object> descriptors = new HashMap<String, Object>(); private final ExecutorService repositoryStarterService; /** Provides the ability to schedule lock clean-up */ private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(2); JcrEngine( ExecutionContext context, ModeShapeConfiguration.ConfigurationDefinition configuration) { super(context, configuration); this.repositories = new HashMap<String, JcrRepositoryHolder>(); this.repositoriesLock = new ReentrantLock(); initDescriptors(); // Create an executor service that we'll use to start the repositories ... ThreadFactory threadFactory = new NamedThreadFactory("modeshape-start-repo"); this.repositoryStarterService = Executors.newCachedThreadPool(threadFactory); } /** * Clean up session-scoped locks created by session that are no longer active by iterating over * the {@link JcrRepository repositories} and calling their {@link * RepositoryLockManager#cleanUpLocks() clean-up method}. * * <p>It should not be possible for a session to be terminated without cleaning up its locks, but * this method will help clean-up dangling locks should a session terminate abnormally. */ void cleanUpLocks() { Collection<JcrRepositoryHolder> repos = null; try { // Make a copy of the repositories to minimize the time that the lock needs to be held. repositoriesLock.lock(); repos = new ArrayList<JcrRepositoryHolder>(repositories.values()); } finally { repositoriesLock.unlock(); } for (JcrRepositoryHolder repository : repos) { repository.cleanUpLocks(); } } @Override protected void preShutdown() { repositoryStarterService.shutdown(); scheduler.shutdown(); super.preShutdown(); try { this.repositoriesLock.lock(); // Shut down all of the repositories ... for (JcrRepositoryHolder holder : repositories.values()) { holder.close(); } this.repositories.clear(); } finally { this.repositoriesLock.unlock(); } } /** * Blocks until the shutdown has completed, or the timeout occurs, or the current thread is * interrupted, whichever happens first. * * @param timeout the maximum time to wait for each component in this engine * @param unit the time unit of the timeout argument * @return <tt>true</tt> if this service complete shut down and <tt>false</tt> if the timeout * elapsed before it was shut down completely * @throws InterruptedException if interrupted while waiting */ @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { if (!scheduler.awaitTermination(timeout, unit)) return false; return super.awaitTermination(timeout, unit); } /** * {@inheritDoc} * * @see org.modeshape.repository.ModeShapeEngine#checkConfiguration(org.modeshape.graph.Subgraph) */ @Override protected void checkConfiguration(Subgraph configuration) { super.checkConfiguration(configuration); // Get the list of sources ... Set<String> sourceNames = new HashSet<String>(); for (Location child : configuration.getNode(ModeShapeLexicon.SOURCES)) { String name = child.getPath().getLastSegment().getName().getLocalName(); sourceNames.add(name); } // Verify all of the repositories reference valid sources ... for (Location child : configuration.getNode(ModeShapeLexicon.REPOSITORIES)) { String repositoryName = readable(child.getPath().getLastSegment().getName()); Node repositoryNode = configuration.getNode(child); Property property = repositoryNode.getProperty(ModeShapeLexicon.SOURCE_NAME); if (property == null) { getProblems() .addError(JcrI18n.repositoryReferencesNonExistantSource, repositoryName, "null"); } else { String sourceName = string(property.getFirstValue()); if (!sourceNames.contains(sourceName)) { getProblems() .addError(JcrI18n.repositoryReferencesNonExistantSource, repositoryName, sourceName); } } } } /** * Start this engine to make it available for use. * * @throws IllegalStateException if this method is called when already shut down. * @throws JcrConfigurationException if there is an error in the configuration or any of the * services that prevents proper startup * @see #start(boolean) * @see #shutdown() */ @Override public void start() { super.start(); final JcrEngine engine = this; Runnable cleanUpTask = new Runnable() { public void run() { engine.cleanUpLocks(); } }; try { scheduler.scheduleAtFixedRate( cleanUpTask, LOCK_SWEEP_INTERVAL_IN_MILLIS, LOCK_SWEEP_INTERVAL_IN_MILLIS, TimeUnit.MILLISECONDS); checkProblemsOnStartup(); } catch (RuntimeException e) { try { super.shutdown(); } catch (Throwable t) { // Don't care about these ... } throw e; } } /** * Start this engine to make it available for use, and optionally start each of the repositories * in the configuration. Any errors starting the repositories will be logged as problems. * * <p>This method starts each repository in parallel, and returns only after all repositories have * been started (or failed startup). * * @param validateRepositoryConfigs true if the configurations of each repository should be * validated and each repository started/initialized, or false otherwise * @throws IllegalStateException if this method is called when already shut down. * @throws JcrConfigurationException if there is an error in the configuration or any of the * services that prevents proper startup * @see #start() * @see #shutdown() */ public void start(boolean validateRepositoryConfigs) { start(validateRepositoryConfigs, -1, TimeUnit.SECONDS); } /** * Start this engine to make it available for use, and optionally start each of the repositories * in the configuration. Any errors starting the repositories will be logged as problems. * * <p>This method starts each repository in parallel, and returns after the supplied timeout or * after all repositories have been started (or failed startup), whichever comes first. * * @param validateRepositoryConfigs true if the configurations of each repository should be * validated and each repository started/initialized, or false otherwise * @param timeout the maximum time to wait; can be 0 or a positive number, but use a negative * number to wait indefinitely until all repositories are started (or failed) * @param timeoutUnit the time unit of the {@code timeout} argument; may not be null, but ignored * if <code>timeout</code> is negative * @throws IllegalStateException if this method is called when already shut down. * @throws JcrConfigurationException if there is an error in the configuration or any of the * services that prevents proper startup * @see #start() * @see #shutdown() */ public void start(boolean validateRepositoryConfigs, long timeout, TimeUnit timeoutUnit) { start(); if (validateRepositoryConfigs) { Set<String> repositoryNames = getRepositoryNames(); if (repositoryNames.isEmpty()) return; final CountDownLatch latch = new CountDownLatch(repositoryNames.size()); try { repositoriesLock.lock(); // Put in a holder with a future for each repository // (this should proceed quickly, as nothing waits for the initialization) ... for (final String repositoryName : repositoryNames) { RepositoryInitializer initializer = new RepositoryInitializer(repositoryName, latch); Future<JcrRepository> future = repositoryStarterService.submit(initializer); JcrRepositoryHolder holder = new JcrRepositoryHolder(repositoryName, future); this.repositories.put(repositoryName, holder); } } finally { repositoriesLock.unlock(); } // Now wait for the all the startups to complete ... try { if (timeout < 0L) { latch.await(); } else { latch.await(timeout, timeoutUnit); } } catch (InterruptedException e) { this.problems.addError(e, JcrI18n.startingAllRepositoriesWasInterrupted, e.getMessage()); } } } /** * {@inheritDoc} * * @see org.modeshape.repository.ModeShapeEngine#newConfigurationException(java.lang.String) */ @Override protected ModeShapeConfigurationException newConfigurationException(String msg) { return new JcrConfigurationException(msg); } /** * Get the version of this engine. * * @return version */ public String getEngineVersion() { return JcrRepository.getBundleProperty(Repository.REP_VERSION_DESC, true); } /** * Get the {@link Repository} implementation for the named repository. * * @param repositoryName the name of the repository, which corresponds to the name of a configured * {@link RepositorySource} * @return the named repository instance * @throws IllegalArgumentException if the repository name is null, blank or invalid * @throws RepositoryException if there is no repository with the specified name * @throws IllegalStateException if this engine was not {@link #start() started} */ public final JcrRepository getRepository(String repositoryName) throws RepositoryException { CheckArg.isNotEmpty(repositoryName, "repositoryName"); checkRunning(); JcrRepositoryHolder holder = null; try { repositoriesLock.lock(); holder = repositories.get(repositoryName); if (holder != null) { // The repository was already placed in the map and thus initialization has been started // and may be finished. But this call will block until the repository has completed // initialization... return holder.getRepository(); } if (!getRepositoryNames().contains(repositoryName)) { // The repository name is not a valid repository ... String msg = JcrI18n.repositoryDoesNotExist.text(repositoryName); throw new RepositoryException(msg); } // Now create the initializer and holder ... RepositoryInitializer initializer = new RepositoryInitializer(repositoryName); Future<JcrRepository> future = repositoryStarterService.submit(initializer); holder = new JcrRepositoryHolder(repositoryName, future); repositories.put(repositoryName, holder); } finally { repositoriesLock.unlock(); } JcrRepository repo = holder.getRepository(); return repo; } /** * Get the names of each of the JCR repositories. * * @return the immutable names of the repositories that exist at the time this method is called */ public Set<String> getRepositoryNames() { checkRunning(); Set<String> results = new HashSet<String>(); // Read the names of the JCR repositories from the configuration (not from the Repository // objects used so far) ... PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory(); Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES); Graph configuration = getConfigurationGraph(); for (Location child : configuration.getChildren().of(repositoriesPath)) { Name repositoryName = child.getPath().getLastSegment().getName(); results.add(readable(repositoryName)); } return Collections.unmodifiableSet(results); } protected JcrRepository doCreateJcrRepository(String repositoryName) throws RepositoryException, PathNotFoundException { RepositoryConnectionFactory connectionFactory = getRepositoryConnectionFactory(); Map<String, String> descriptors = new HashMap<String, String>(); Map<Option, String> options = new HashMap<Option, String>(); // Read the subgraph that represents the repository ... PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory(); Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES); Path repositoryPath = pathFactory.create(repositoriesPath, repositoryName); Name repoName = getExecutionContext().getValueFactories().getNameFactory().create(repositoryName); Graph configuration = null; Subgraph subgraph = getConfigurationSubgraph(false); // Read the options ... Path optionsPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, ModeShapeLexicon.OPTIONS); Node optionsNode = subgraph.getNode(optionsPath); if (optionsNode != null) { for (Location optionLocation : optionsNode.getChildren()) { Node optionNode = subgraph.getNode(optionLocation); Path.Segment segment = optionLocation.getPath().getLastSegment(); Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE); if (valueProperty == null) { log.warn(JcrI18n.noOptionValueProvided, segment.getName().getLocalName()); continue; } Option option = Option.findOption(segment.getName().getLocalName()); if (option == null) { log.warn(JcrI18n.invalidOptionProvided, segment.getName().getLocalName()); continue; } options.put(option, valueProperty.getFirstValue().toString()); } } // Disable the derived content removal option if not explicitly set and no sequencers ... if (!options.containsKey(Option.REMOVE_DERIVED_CONTENT_WITH_ORIGINAL) && getSequencingService().getSequencers().isEmpty()) { options.put(Option.REMOVE_DERIVED_CONTENT_WITH_ORIGINAL, Boolean.FALSE.toString()); } // Read the descriptors ... Path descriptorsPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, ModeShapeLexicon.DESCRIPTORS); Node descriptorsNode = subgraph.getNode(descriptorsPath); if (descriptorsNode != null) { for (Location descriptorLocation : descriptorsNode.getChildren()) { Node optionNode = subgraph.getNode(descriptorLocation); Path.Segment segment = descriptorLocation.getPath().getLastSegment(); Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE); if (valueProperty == null) continue; descriptors.put(segment.getName().getLocalName(), valueProperty.getFirstValue().toString()); } } // Read the namespaces ... ExecutionContext context = getExecutionContext(); Path namespacesPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, ModeShapeLexicon.NAMESPACES); Node namespacesNode = subgraph.getNode(namespacesPath); descriptors.put(org.modeshape.jcr.api.Repository.REPOSITORY_NAME, repositoryName); if (namespacesNode != null) { configuration = getConfigurationGraph(); GraphNamespaceRegistry registry = new GraphNamespaceRegistry( configuration, namespacesNode.getLocation().getPath(), ModeShapeLexicon.URI, ModeShapeLexicon.GENERATED); context = context.with(registry); } // Get the name of the source ... Path repoPath = pathFactory.createRelativePath(ModeShapeLexicon.REPOSITORIES, repoName); Node repoNode = subgraph.getNode(repoPath); if (repoNode == null) { // There is no repository with the supplied name ... throw new PathNotFoundException( Location.create(repoPath), repositoriesPath, JcrI18n.repositoryDoesNotExist.text(readable(repoName))); } Property property = repoNode.getProperty(ModeShapeLexicon.SOURCE_NAME); if (property == null || property.isEmpty()) { if (configuration == null) configuration = getConfigurationGraph(); String readableName = readable(ModeShapeLexicon.SOURCE_NAME); String readablePath = readable(subgraph.getLocation()); String msg = JcrI18n.propertyNotFoundOnNode.text( readableName, readablePath, configuration.getCurrentWorkspaceName()); throw new RepositoryException(msg); } String sourceName = context.getValueFactories().getStringFactory().create(property.getFirstValue()); // Verify the sourc exists ... RepositorySource source = getRepositorySource(sourceName); if (source == null) { throw new RepositoryException( JcrI18n.repositoryReferencesNonExistantSource.text(repositoryName, sourceName)); } // Read the initial content ... String initialContentForNewWorkspaces = null; for (Location initialContentLocation : repoNode.getChildren(ModeShapeLexicon.INITIAL_CONTENT)) { Node initialContent = subgraph.getNode(initialContentLocation); if (initialContent == null) continue; // Determine where to load the initial content from ... Property contentReference = initialContent.getProperty(ModeShapeLexicon.CONTENT); if (contentReference == null || contentReference.isEmpty()) { if (configuration == null) configuration = getConfigurationGraph(); String readableName = readable(ModeShapeLexicon.CONTENT); String readablePath = readable(initialContentLocation); String msg = JcrI18n.propertyNotFoundOnNode.text( readableName, readablePath, configuration.getCurrentWorkspaceName()); throw new RepositoryException(msg); } String contentRef = string(contentReference.getFirstValue()); // Determine which workspaces this should apply to ... Property workspaces = initialContent.getProperty(ModeShapeLexicon.WORKSPACES); if (workspaces == null || workspaces.isEmpty()) { if (configuration == null) configuration = getConfigurationGraph(); String readableName = readable(ModeShapeLexicon.WORKSPACES); String readablePath = readable(initialContentLocation); String msg = JcrI18n.propertyNotFoundOnNode.text( readableName, readablePath, configuration.getCurrentWorkspaceName()); throw new RepositoryException(msg); } // Load the initial content into a transient source ... XmlFileRepositorySource initialContentSource = new XmlFileRepositorySource(); initialContentSource.setName("Initial content for " + repositoryName); initialContentSource.setContentLocation(contentRef); Graph initialContentGraph = Graph.create(initialContentSource, context); Graph sourceGraph = Graph.create(sourceName, connectionFactory, context); // And initialize the source with the content (if not already there) ... for (Object value : workspaces) { String workspaceName = string(value); if (workspaceName != null && workspaceName.trim().length() != 0) { // Load the content into the workspace with this name ... sourceGraph.useWorkspace(workspaceName); try { sourceGraph.merge(initialContentGraph); } catch (RuntimeException e) { throw new RepositoryException( JcrI18n.unableToImportInitialContent.text(readable(repoName), contentRef), e); } } } // Determine if this initial content should apply to new workspaces ... Property applyToNewWorkspaces = initialContent.getProperty(ModeShapeLexicon.APPLY_TO_NEW_WORKSPACES); if (applyToNewWorkspaces != null && !applyToNewWorkspaces.isEmpty() && isTrue(applyToNewWorkspaces.getFirstValue())) { initialContentForNewWorkspaces = contentRef; // may overwrite the value if seen more than once! } } // Find the capabilities ... RepositorySourceCapabilities capabilities = source.getCapabilities(); // Create the repository ... JcrRepository repository = new JcrRepository( context, connectionFactory, sourceName, getRepositoryService().getRepositoryLibrary(), capabilities, descriptors, options, initialContentForNewWorkspaces); // Register all the the node types ... Path nodeTypesPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, JcrLexicon.NODE_TYPES); Node nodeTypesNode = subgraph.getNode(nodeTypesPath); if (nodeTypesNode != null) { boolean needToRefreshSubgraph = false; if (configuration == null) configuration = getConfigurationGraph(); // Expand any references to a CND file Property resourceProperty = nodeTypesNode.getProperty(ModeShapeLexicon.RESOURCE); if (resourceProperty != null) { ClassLoader classLoader = this.context.getClassLoader(); for (Object resourceValue : resourceProperty) { String resources = this.context.getValueFactories().getStringFactory().create(resourceValue); for (String resource : resources.split("\\s*,\\s*")) { Graph.Batch batch = configuration.batch(); GraphBatchDestination destination = new GraphBatchDestination(batch); Path nodeTypesAbsPath = pathFactory.create(repositoryPath, JcrLexicon.NODE_TYPES); CndImporter importer = new CndImporter(destination, nodeTypesAbsPath, true, false); InputStream is = IoUtil.getResourceAsStream(resource, classLoader, getClass()); Problems cndProblems = new SimpleProblems(); if (is == null) { String msg = JcrI18n.unableToFindNodeTypeDefinitionsOnClasspathOrFileOrUrl.text(resource); throw new RepositoryException(msg); } try { importer.importFrom(is, cndProblems, resource); batch.execute(); needToRefreshSubgraph = true; } catch (IOException ioe) { String msg = JcrI18n.errorLoadingNodeTypeDefintions.text(resource, ioe.getMessage()); throw new RepositoryException(msg, ioe); } if (!cndProblems.isEmpty()) { // Add any warnings or information to this engine's list ... getProblems().addAll(cndProblems); if (cndProblems.hasErrors()) { String msg = null; Throwable cause = null; for (Problem problem : cndProblems) { if (problem.getStatus() == Status.ERROR) { msg = problem.getMessageString(); cause = problem.getThrowable(); break; } } throw new RepositoryException( JcrI18n.errorLoadingNodeTypeDefintions.text(resource, msg), cause); } } } } } // Load any namespaces from the configuration into the repository's context ... NamespaceRegistry repoRegistry = repository.getExecutionContext().getNamespaceRegistry(); repoRegistry.register(configuration.getContext().getNamespaceRegistry().getNamespaces()); // Re-read the subgraph, in case any new nodes were added Subgraph nodeTypesSubgraph = subgraph; if (needToRefreshSubgraph) { nodeTypesSubgraph = configuration.getSubgraphOfDepth(4).at(nodeTypesNode.getLocation().getPath()); } repository .getRepositoryTypeManager() .registerNodeTypes(nodeTypesSubgraph, nodeTypesNode.getLocation(), false); } return repository; } protected final String readable(Name name) { return name.getString(context.getNamespaceRegistry()); } protected final String readable(Path path) { return path.getString(context.getNamespaceRegistry()); } protected final String readable(Location location) { return location.getString(context.getNamespaceRegistry()); } protected final String string(Object value) { return context.getValueFactories().getStringFactory().create(value); } protected final boolean isTrue(Object value) { return context.getValueFactories().getBooleanFactory().create(value); } /** @return descriptors */ public Map<String, Object> initDescriptors() { ValueFactories factories = this.getExecutionContext().getValueFactories(); descriptors.put(Repository.SPEC_NAME_DESC, valueFor(factories, JcrI18n.SPEC_NAME_DESC.text())); descriptors.put(Repository.SPEC_VERSION_DESC, valueFor(factories, "2.0")); if (!descriptors.containsKey(Repository.REP_NAME_DESC)) { descriptors.put( Repository.REP_NAME_DESC, valueFor(factories, JcrRepository.getBundleProperty(Repository.REP_NAME_DESC, true))); } if (!descriptors.containsKey(Repository.REP_VENDOR_DESC)) { descriptors.put( Repository.REP_VENDOR_DESC, valueFor(factories, JcrRepository.getBundleProperty(Repository.REP_VENDOR_DESC, true))); } if (!descriptors.containsKey(Repository.REP_VENDOR_URL_DESC)) { descriptors.put( Repository.REP_VENDOR_URL_DESC, valueFor( factories, JcrRepository.getBundleProperty(Repository.REP_VENDOR_URL_DESC, true))); } if (!descriptors.containsKey(Repository.REP_VERSION_DESC)) { descriptors.put(Repository.REP_VERSION_DESC, valueFor(factories, getEngineVersion())); } return descriptors; } private static JcrValue valueFor(ValueFactories valueFactories, int type, Object value) { return new JcrValue(valueFactories, null, type, value); } private static JcrValue valueFor(ValueFactories valueFactories, String value) { return valueFor(valueFactories, PropertyType.STRING, value); } /** * This method is equivalent to calling {@link #shutdown()} followed by {@link * #awaitTermination(long, TimeUnit)}, except that after those methods are called any remaining * JCR sessions are terminated automatically. This is useful when shutting down while there are * long-running JCR sessions (such as for event listeners). * * @param timeout the maximum time to wait for each component in this engine * @param unit the time unit of the timeout argument * @throws InterruptedException if interrupted while waiting */ public void shutdownAndAwaitTermination(long timeout, TimeUnit unit) throws InterruptedException { shutdown(); awaitTermination(timeout, unit); for (JcrRepositoryHolder repository : repositories.values()) { if (repository != null) repository.terminateAllSessions(); } } protected Logger getLogger() { return log; } protected Problems problems() { return problems; } protected class JcrRepositoryHolder { private final String repositoryName; private JcrRepository repository; private Future<JcrRepository> future; private Throwable error; protected JcrRepositoryHolder(String repositoryName, Future<JcrRepository> future) { this.repositoryName = repositoryName; this.future = future; assert this.future != null; } public String getName() { return repositoryName; } public synchronized JcrRepository getRepository() throws RepositoryException { if (repository == null) { if (future != null) { try { // Otherwise it is still initializing, so wait for it ... this.repository = future.get(); } catch (Throwable e) { error = e.getCause(); String msg = JcrI18n.errorStartingRepositoryCheckConfiguration.text( repositoryName, error.getMessage()); throw new RepositoryException(msg, error); } finally { this.future = null; } } if (repository == null) { // There is no future, but the repository could not be initialized correctly ... String msg = JcrI18n.errorStartingRepositoryCheckConfiguration.text( repositoryName, error.getMessage()); throw new RepositoryException(msg, error); } } return this.repository; } public synchronized void close() { if (future != null) { try { future.cancel(false); } finally { future = null; } } if (repository != null) { try { repository.close(); } finally { repository = null; } } } public synchronized void terminateAllSessions() { // only need to do this on repositories that have been used; i.e., not including // just-initialized repositories if (repository != null) repository.terminateAllSessions(); } public synchronized void cleanUpLocks() { // only need to do this on repositories that have been used; i.e., not including // just-initialized repositories if (repository != null) { try { repository.getRepositoryLockManager().cleanUpLocks(); } catch (Throwable t) { getLogger().error(t, JcrI18n.errorCleaningUpLocks, repository.getRepositorySourceName()); } } } /** * {@inheritDoc} * * @see java.lang.Object#toString() */ @Override public String toString() { return repositoryName; } } protected class RepositoryInitializer implements Callable<JcrRepository> { private final String repositoryName; private final CountDownLatch latch; protected RepositoryInitializer(String repositoryName) { this(repositoryName, null); } protected RepositoryInitializer(String repositoryName, CountDownLatch latch) { this.repositoryName = repositoryName; this.latch = latch; } public JcrRepository call() throws Exception { JcrRepository repository = null; try { repository = doCreateJcrRepository(repositoryName); getLogger().info(JcrI18n.completedStartingRepository, repositoryName); return repository; } catch (RepositoryException t) { // Record this in the problems ... problems() .addError( t, JcrI18n.errorStartingRepositoryCheckConfiguration, repositoryName, t.getMessage()); throw t; } catch (Throwable t) { // Record this in the problems ... problems() .addError( t, JcrI18n.errorStartingRepositoryCheckConfiguration, repositoryName, t.getMessage()); String msg = JcrI18n.errorStartingRepositoryCheckConfiguration.text(repositoryName, t.getMessage()); throw new RepositoryException(msg, t); } finally { if (latch != null) latch.countDown(); } } } }
protected JcrRepository doCreateJcrRepository(String repositoryName) throws RepositoryException, PathNotFoundException { RepositoryConnectionFactory connectionFactory = getRepositoryConnectionFactory(); Map<String, String> descriptors = new HashMap<String, String>(); Map<Option, String> options = new HashMap<Option, String>(); // Read the subgraph that represents the repository ... PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory(); Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES); Path repositoryPath = pathFactory.create(repositoriesPath, repositoryName); Name repoName = getExecutionContext().getValueFactories().getNameFactory().create(repositoryName); Graph configuration = null; Subgraph subgraph = getConfigurationSubgraph(false); // Read the options ... Path optionsPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, ModeShapeLexicon.OPTIONS); Node optionsNode = subgraph.getNode(optionsPath); if (optionsNode != null) { for (Location optionLocation : optionsNode.getChildren()) { Node optionNode = subgraph.getNode(optionLocation); Path.Segment segment = optionLocation.getPath().getLastSegment(); Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE); if (valueProperty == null) { log.warn(JcrI18n.noOptionValueProvided, segment.getName().getLocalName()); continue; } Option option = Option.findOption(segment.getName().getLocalName()); if (option == null) { log.warn(JcrI18n.invalidOptionProvided, segment.getName().getLocalName()); continue; } options.put(option, valueProperty.getFirstValue().toString()); } } // Disable the derived content removal option if not explicitly set and no sequencers ... if (!options.containsKey(Option.REMOVE_DERIVED_CONTENT_WITH_ORIGINAL) && getSequencingService().getSequencers().isEmpty()) { options.put(Option.REMOVE_DERIVED_CONTENT_WITH_ORIGINAL, Boolean.FALSE.toString()); } // Read the descriptors ... Path descriptorsPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, ModeShapeLexicon.DESCRIPTORS); Node descriptorsNode = subgraph.getNode(descriptorsPath); if (descriptorsNode != null) { for (Location descriptorLocation : descriptorsNode.getChildren()) { Node optionNode = subgraph.getNode(descriptorLocation); Path.Segment segment = descriptorLocation.getPath().getLastSegment(); Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE); if (valueProperty == null) continue; descriptors.put(segment.getName().getLocalName(), valueProperty.getFirstValue().toString()); } } // Read the namespaces ... ExecutionContext context = getExecutionContext(); Path namespacesPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, ModeShapeLexicon.NAMESPACES); Node namespacesNode = subgraph.getNode(namespacesPath); descriptors.put(org.modeshape.jcr.api.Repository.REPOSITORY_NAME, repositoryName); if (namespacesNode != null) { configuration = getConfigurationGraph(); GraphNamespaceRegistry registry = new GraphNamespaceRegistry( configuration, namespacesNode.getLocation().getPath(), ModeShapeLexicon.URI, ModeShapeLexicon.GENERATED); context = context.with(registry); } // Get the name of the source ... Path repoPath = pathFactory.createRelativePath(ModeShapeLexicon.REPOSITORIES, repoName); Node repoNode = subgraph.getNode(repoPath); if (repoNode == null) { // There is no repository with the supplied name ... throw new PathNotFoundException( Location.create(repoPath), repositoriesPath, JcrI18n.repositoryDoesNotExist.text(readable(repoName))); } Property property = repoNode.getProperty(ModeShapeLexicon.SOURCE_NAME); if (property == null || property.isEmpty()) { if (configuration == null) configuration = getConfigurationGraph(); String readableName = readable(ModeShapeLexicon.SOURCE_NAME); String readablePath = readable(subgraph.getLocation()); String msg = JcrI18n.propertyNotFoundOnNode.text( readableName, readablePath, configuration.getCurrentWorkspaceName()); throw new RepositoryException(msg); } String sourceName = context.getValueFactories().getStringFactory().create(property.getFirstValue()); // Verify the sourc exists ... RepositorySource source = getRepositorySource(sourceName); if (source == null) { throw new RepositoryException( JcrI18n.repositoryReferencesNonExistantSource.text(repositoryName, sourceName)); } // Read the initial content ... String initialContentForNewWorkspaces = null; for (Location initialContentLocation : repoNode.getChildren(ModeShapeLexicon.INITIAL_CONTENT)) { Node initialContent = subgraph.getNode(initialContentLocation); if (initialContent == null) continue; // Determine where to load the initial content from ... Property contentReference = initialContent.getProperty(ModeShapeLexicon.CONTENT); if (contentReference == null || contentReference.isEmpty()) { if (configuration == null) configuration = getConfigurationGraph(); String readableName = readable(ModeShapeLexicon.CONTENT); String readablePath = readable(initialContentLocation); String msg = JcrI18n.propertyNotFoundOnNode.text( readableName, readablePath, configuration.getCurrentWorkspaceName()); throw new RepositoryException(msg); } String contentRef = string(contentReference.getFirstValue()); // Determine which workspaces this should apply to ... Property workspaces = initialContent.getProperty(ModeShapeLexicon.WORKSPACES); if (workspaces == null || workspaces.isEmpty()) { if (configuration == null) configuration = getConfigurationGraph(); String readableName = readable(ModeShapeLexicon.WORKSPACES); String readablePath = readable(initialContentLocation); String msg = JcrI18n.propertyNotFoundOnNode.text( readableName, readablePath, configuration.getCurrentWorkspaceName()); throw new RepositoryException(msg); } // Load the initial content into a transient source ... XmlFileRepositorySource initialContentSource = new XmlFileRepositorySource(); initialContentSource.setName("Initial content for " + repositoryName); initialContentSource.setContentLocation(contentRef); Graph initialContentGraph = Graph.create(initialContentSource, context); Graph sourceGraph = Graph.create(sourceName, connectionFactory, context); // And initialize the source with the content (if not already there) ... for (Object value : workspaces) { String workspaceName = string(value); if (workspaceName != null && workspaceName.trim().length() != 0) { // Load the content into the workspace with this name ... sourceGraph.useWorkspace(workspaceName); try { sourceGraph.merge(initialContentGraph); } catch (RuntimeException e) { throw new RepositoryException( JcrI18n.unableToImportInitialContent.text(readable(repoName), contentRef), e); } } } // Determine if this initial content should apply to new workspaces ... Property applyToNewWorkspaces = initialContent.getProperty(ModeShapeLexicon.APPLY_TO_NEW_WORKSPACES); if (applyToNewWorkspaces != null && !applyToNewWorkspaces.isEmpty() && isTrue(applyToNewWorkspaces.getFirstValue())) { initialContentForNewWorkspaces = contentRef; // may overwrite the value if seen more than once! } } // Find the capabilities ... RepositorySourceCapabilities capabilities = source.getCapabilities(); // Create the repository ... JcrRepository repository = new JcrRepository( context, connectionFactory, sourceName, getRepositoryService().getRepositoryLibrary(), capabilities, descriptors, options, initialContentForNewWorkspaces); // Register all the the node types ... Path nodeTypesPath = pathFactory.createRelativePath( ModeShapeLexicon.REPOSITORIES, repoName, JcrLexicon.NODE_TYPES); Node nodeTypesNode = subgraph.getNode(nodeTypesPath); if (nodeTypesNode != null) { boolean needToRefreshSubgraph = false; if (configuration == null) configuration = getConfigurationGraph(); // Expand any references to a CND file Property resourceProperty = nodeTypesNode.getProperty(ModeShapeLexicon.RESOURCE); if (resourceProperty != null) { ClassLoader classLoader = this.context.getClassLoader(); for (Object resourceValue : resourceProperty) { String resources = this.context.getValueFactories().getStringFactory().create(resourceValue); for (String resource : resources.split("\\s*,\\s*")) { Graph.Batch batch = configuration.batch(); GraphBatchDestination destination = new GraphBatchDestination(batch); Path nodeTypesAbsPath = pathFactory.create(repositoryPath, JcrLexicon.NODE_TYPES); CndImporter importer = new CndImporter(destination, nodeTypesAbsPath, true, false); InputStream is = IoUtil.getResourceAsStream(resource, classLoader, getClass()); Problems cndProblems = new SimpleProblems(); if (is == null) { String msg = JcrI18n.unableToFindNodeTypeDefinitionsOnClasspathOrFileOrUrl.text(resource); throw new RepositoryException(msg); } try { importer.importFrom(is, cndProblems, resource); batch.execute(); needToRefreshSubgraph = true; } catch (IOException ioe) { String msg = JcrI18n.errorLoadingNodeTypeDefintions.text(resource, ioe.getMessage()); throw new RepositoryException(msg, ioe); } if (!cndProblems.isEmpty()) { // Add any warnings or information to this engine's list ... getProblems().addAll(cndProblems); if (cndProblems.hasErrors()) { String msg = null; Throwable cause = null; for (Problem problem : cndProblems) { if (problem.getStatus() == Status.ERROR) { msg = problem.getMessageString(); cause = problem.getThrowable(); break; } } throw new RepositoryException( JcrI18n.errorLoadingNodeTypeDefintions.text(resource, msg), cause); } } } } } // Load any namespaces from the configuration into the repository's context ... NamespaceRegistry repoRegistry = repository.getExecutionContext().getNamespaceRegistry(); repoRegistry.register(configuration.getContext().getNamespaceRegistry().getNamespaces()); // Re-read the subgraph, in case any new nodes were added Subgraph nodeTypesSubgraph = subgraph; if (needToRefreshSubgraph) { nodeTypesSubgraph = configuration.getSubgraphOfDepth(4).at(nodeTypesNode.getLocation().getPath()); } repository .getRepositoryTypeManager() .registerNodeTypes(nodeTypesSubgraph, nodeTypesNode.getLocation(), false); } return repository; }