001 /*
002 * JBoss DNA (http://www.jboss.org/dna)
003 * See the COPYRIGHT.txt file distributed with this work for information
004 * regarding copyright ownership. Some portions may be licensed
005 * to Red Hat, Inc. under one or more contributor license agreements.
006 * See the AUTHORS.txt file in the distribution for a full listing of
007 * individual contributors.
008 *
009 * Unless otherwise indicated, all code in JBoss DNA is licensed
010 * to you under the terms of the GNU Lesser General Public License as
011 * published by the Free Software Foundation; either version 2.1 of
012 * the License, or (at your option) any later version.
013 *
014 * JBoss DNA is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this software; if not, write to the Free
021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023 */
024 package org.jboss.dna.jcr;
025
026 import java.util.Collections;
027 import java.util.HashMap;
028 import java.util.HashSet;
029 import java.util.Map;
030 import java.util.Set;
031 import java.util.concurrent.locks.Lock;
032 import java.util.concurrent.locks.ReentrantLock;
033 import javax.jcr.Repository;
034 import javax.jcr.RepositoryException;
035 import org.jboss.dna.common.util.CheckArg;
036 import org.jboss.dna.graph.ExecutionContext;
037 import org.jboss.dna.graph.Graph;
038 import org.jboss.dna.graph.Location;
039 import org.jboss.dna.graph.Node;
040 import org.jboss.dna.graph.Subgraph;
041 import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
042 import org.jboss.dna.graph.connector.RepositorySource;
043 import org.jboss.dna.graph.property.Name;
044 import org.jboss.dna.graph.property.Path;
045 import org.jboss.dna.graph.property.PathFactory;
046 import org.jboss.dna.graph.property.PathNotFoundException;
047 import org.jboss.dna.graph.property.Property;
048 import org.jboss.dna.graph.property.basic.GraphNamespaceRegistry;
049 import org.jboss.dna.jcr.JcrRepository.Option;
050 import org.jboss.dna.repository.DnaConfiguration;
051 import org.jboss.dna.repository.DnaEngine;
052
053 /**
054 * The basic component that encapsulates the JBoss DNA services, including the {@link Repository} instances.
055 */
056 public class JcrEngine extends DnaEngine {
057
058 private final Map<String, JcrRepository> repositories;
059 private final Lock repositoriesLock;
060
061 JcrEngine( ExecutionContext context,
062 DnaConfiguration.ConfigurationDefinition configuration ) {
063 super(context, configuration);
064 this.repositories = new HashMap<String, JcrRepository>();
065 this.repositoriesLock = new ReentrantLock();
066 }
067
068 /**
069 * Get the {@link Repository} implementation for the named repository.
070 *
071 * @param repositoryName the name of the repository, which corresponds to the name of a configured {@link RepositorySource}
072 * @return the named repository instance
073 * @throws IllegalArgumentException if the repository name is null, blank or invalid
074 * @throws RepositoryException if there is no repository with the specified name
075 * @throws IllegalStateException if this engine was not {@link #start() started}
076 */
077 public final JcrRepository getRepository( String repositoryName ) throws RepositoryException {
078 CheckArg.isNotEmpty(repositoryName, "repositoryName");
079 checkRunning();
080 try {
081 repositoriesLock.lock();
082 JcrRepository repository = repositories.get(repositoryName);
083 if (repository == null) {
084 try {
085 repository = doCreateJcrRepository(repositoryName);
086 } catch (PathNotFoundException e) {
087 // The repository name is not a valid repository ...
088 String msg = JcrI18n.repositoryDoesNotExist.text(repositoryName);
089 throw new RepositoryException(msg);
090 }
091 repositories.put(repositoryName, repository);
092 }
093 return repository;
094 } finally {
095 repositoriesLock.unlock();
096 }
097 }
098
099 /**
100 * Get the names of each of the JCR repositories.
101 *
102 * @return the immutable names of the repositories that exist at the time this method is called
103 */
104 public Set<String> getRepositoryNames() {
105 checkRunning();
106 Set<String> results = new HashSet<String>();
107 // Read the names of the JCR repositories from the configuration (not from the Repository objects used so far) ...
108 PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory();
109 Path repositoriesPath = pathFactory.create(configuration.getPath(), DnaLexicon.REPOSITORIES);
110 Graph configuration = getConfigurationGraph();
111 for (Location child : configuration.getChildren().of(repositoriesPath)) {
112 Name repositoryName = child.getPath().getLastSegment().getName();
113 results.add(readable(repositoryName));
114 }
115 return Collections.unmodifiableSet(results);
116 }
117
118 protected JcrRepository doCreateJcrRepository( String repositoryName ) throws RepositoryException, PathNotFoundException {
119 RepositoryConnectionFactory connectionFactory = getRepositoryConnectionFactory();
120 Map<String, String> descriptors = null;
121 Map<Option, String> options = new HashMap<Option, String>();
122
123 // Read the subgraph that represents the repository ...
124 PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory();
125 Path repositoriesPath = pathFactory.create(configuration.getPath(), DnaLexicon.REPOSITORIES);
126 Path repositoryPath = pathFactory.create(repositoriesPath, repositoryName);
127 Graph configuration = getConfigurationGraph();
128 Subgraph subgraph = configuration.getSubgraphOfDepth(6).at(repositoryPath);
129
130 // Read the options ...
131 Node optionsNode = subgraph.getNode(DnaLexicon.OPTIONS);
132 if (optionsNode != null) {
133 for (Location optionLocation : optionsNode.getChildren()) {
134 Node optionNode = configuration.getNodeAt(optionLocation);
135 Path.Segment segment = optionLocation.getPath().getLastSegment();
136 Property valueProperty = optionNode.getProperty(DnaLexicon.VALUE);
137 if (valueProperty == null) continue;
138 Option option = Option.findOption(segment.getName().getLocalName());
139 if (option == null) continue;
140 options.put(option, valueProperty.getFirstValue().toString());
141 }
142 }
143
144 // Read the namespaces ...
145 ExecutionContext context = getExecutionContext();
146 Node namespacesNode = subgraph.getNode(DnaLexicon.NAMESPACES);
147 if (namespacesNode != null) {
148 GraphNamespaceRegistry registry = new GraphNamespaceRegistry(configuration, namespacesNode.getLocation().getPath(),
149 DnaLexicon.NAMESPACE_URI);
150 context = context.with(registry);
151 }
152
153 // Get the name of the source ...
154 Property property = subgraph.getRoot().getProperty(DnaLexicon.SOURCE_NAME);
155 if (property == null || property.isEmpty()) {
156 String readableName = readable(DnaLexicon.SOURCE_NAME);
157 String readablePath = readable(subgraph.getLocation());
158 String msg = JcrI18n.propertyNotFoundOnNode.text(readableName, readablePath, configuration.getCurrentWorkspaceName());
159 throw new RepositoryException(msg);
160 }
161 String sourceName = context.getValueFactories().getStringFactory().create(property.getFirstValue());
162
163 // Create the repository ...
164 JcrRepository repository = new JcrRepository(context, connectionFactory, sourceName, descriptors, options);
165
166 // Register all the the node types ...
167 Node nodeTypesNode = subgraph.getNode(DnaLexicon.NODE_TYPES);
168 if (nodeTypesNode != null) {
169 repository.getRepositoryTypeManager().registerNodeTypes(subgraph, nodeTypesNode.getLocation());// throws exception
170 }
171
172 return repository;
173 }
174
175 protected final String readable( Name name ) {
176 return name.getString(context.getNamespaceRegistry());
177 }
178
179 protected final String readable( Path path ) {
180 return path.getString(context.getNamespaceRegistry());
181 }
182
183 protected final String readable( Location location ) {
184 return location.getString(context.getNamespaceRegistry());
185 }
186 }