1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.jcr;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.concurrent.ScheduledExecutorService;
36 import java.util.concurrent.ScheduledThreadPoolExecutor;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.locks.Lock;
39 import java.util.concurrent.locks.ReentrantLock;
40 import javax.jcr.Repository;
41 import javax.jcr.RepositoryException;
42 import net.jcip.annotations.ThreadSafe;
43 import org.modeshape.cnd.CndImporter;
44 import org.modeshape.common.util.CheckArg;
45 import org.modeshape.common.util.Logger;
46 import org.modeshape.graph.ExecutionContext;
47 import org.modeshape.graph.Graph;
48 import org.modeshape.graph.Location;
49 import org.modeshape.graph.Node;
50 import org.modeshape.graph.Subgraph;
51 import org.modeshape.graph.connector.RepositoryConnectionFactory;
52 import org.modeshape.graph.connector.RepositorySource;
53 import org.modeshape.graph.connector.RepositorySourceCapabilities;
54 import org.modeshape.graph.io.GraphBatchDestination;
55 import org.modeshape.graph.property.Name;
56 import org.modeshape.graph.property.Path;
57 import org.modeshape.graph.property.PathFactory;
58 import org.modeshape.graph.property.PathNotFoundException;
59 import org.modeshape.graph.property.Property;
60 import org.modeshape.graph.property.basic.GraphNamespaceRegistry;
61 import org.modeshape.jcr.JcrRepository.Option;
62 import org.modeshape.jcr.api.Repositories;
63 import org.modeshape.repository.ModeShapeConfiguration;
64 import org.modeshape.repository.ModeShapeEngine;
65
66
67
68
69 @ThreadSafe
70 public class JcrEngine extends ModeShapeEngine implements Repositories {
71
72 final static int LOCK_SWEEP_INTERVAL_IN_MILLIS = 30000;
73 final static int LOCK_EXTENSION_INTERVAL_IN_MILLIS = LOCK_SWEEP_INTERVAL_IN_MILLIS * 2;
74
75 private static final Logger log = Logger.getLogger(ModeShapeEngine.class);
76
77 private final Map<String, JcrRepository> repositories;
78 private final Lock repositoriesLock;
79
80
81
82
83 private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(2);
84
85 JcrEngine( ExecutionContext context,
86 ModeShapeConfiguration.ConfigurationDefinition configuration ) {
87 super(context, configuration);
88 this.repositories = new HashMap<String, JcrRepository>();
89 this.repositoriesLock = new ReentrantLock();
90 }
91
92
93
94
95
96
97
98
99
100 void cleanUpLocks() {
101 Collection<JcrRepository> repos;
102
103 try {
104
105 repositoriesLock.lock();
106 repos = new ArrayList<JcrRepository>(repositories.values());
107 } finally {
108 repositoriesLock.unlock();
109 }
110
111 for (JcrRepository repository : repos) {
112 try {
113 repository.cleanUpLocks();
114 } catch (Throwable t) {
115 log.error(t, JcrI18n.errorCleaningUpLocks, repository.getRepositorySourceName());
116 }
117 }
118 }
119
120 @Override
121 public void shutdown() {
122 scheduler.shutdown();
123 super.shutdown();
124
125 try {
126 this.repositoriesLock.lock();
127
128 for (JcrRepository repository : repositories.values()) {
129 repository.close();
130 }
131 this.repositories.clear();
132 } finally {
133 this.repositoriesLock.unlock();
134 }
135 }
136
137 @Override
138 public boolean awaitTermination( long timeout,
139 TimeUnit unit ) throws InterruptedException {
140 if (!scheduler.awaitTermination(timeout, unit)) return false;
141
142 return super.awaitTermination(timeout, unit);
143 }
144
145 @Override
146 public void start() {
147 super.start();
148
149 final JcrEngine engine = this;
150 Runnable cleanUpTask = new Runnable() {
151
152 public void run() {
153 engine.cleanUpLocks();
154 }
155
156 };
157 scheduler.scheduleAtFixedRate(cleanUpTask,
158 LOCK_SWEEP_INTERVAL_IN_MILLIS,
159 LOCK_SWEEP_INTERVAL_IN_MILLIS,
160 TimeUnit.MILLISECONDS);
161 }
162
163
164
165
166
167
168
169
170
171
172 public final JcrRepository getRepository( String repositoryName ) throws RepositoryException {
173 CheckArg.isNotEmpty(repositoryName, "repositoryName");
174 checkRunning();
175 try {
176 repositoriesLock.lock();
177 JcrRepository repository = repositories.get(repositoryName);
178 if (repository == null) {
179 try {
180 repository = doCreateJcrRepository(repositoryName);
181 } catch (PathNotFoundException e) {
182
183 String msg = JcrI18n.repositoryDoesNotExist.text(repositoryName);
184 throw new RepositoryException(msg);
185 }
186 repositories.put(repositoryName, repository);
187 }
188 return repository;
189 } finally {
190 repositoriesLock.unlock();
191 }
192 }
193
194
195
196
197
198
199 public Set<String> getRepositoryNames() {
200 checkRunning();
201 Set<String> results = new HashSet<String>();
202
203 PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory();
204 Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES);
205 Graph configuration = getConfigurationGraph();
206 for (Location child : configuration.getChildren().of(repositoriesPath)) {
207 Name repositoryName = child.getPath().getLastSegment().getName();
208 results.add(readable(repositoryName));
209 }
210 return Collections.unmodifiableSet(results);
211 }
212
213 protected JcrRepository doCreateJcrRepository( String repositoryName ) throws RepositoryException, PathNotFoundException {
214 RepositoryConnectionFactory connectionFactory = getRepositoryConnectionFactory();
215 Map<String, String> descriptors = new HashMap<String, String>();
216 Map<Option, String> options = new HashMap<Option, String>();
217
218
219 PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory();
220 Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES);
221 Path repositoryPath = pathFactory.create(repositoriesPath, repositoryName);
222 Graph configuration = getConfigurationGraph();
223 Subgraph subgraph = configuration.getSubgraphOfDepth(6).at(repositoryPath);
224
225
226 Node optionsNode = subgraph.getNode(ModeShapeLexicon.OPTIONS);
227 if (optionsNode != null) {
228 for (Location optionLocation : optionsNode.getChildren()) {
229 Node optionNode = configuration.getNodeAt(optionLocation);
230 Path.Segment segment = optionLocation.getPath().getLastSegment();
231 Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE);
232 if (valueProperty == null) continue;
233 Option option = Option.findOption(segment.getName().getLocalName());
234 if (option == null) continue;
235 options.put(option, valueProperty.getFirstValue().toString());
236 }
237 }
238
239
240 Node descriptorsNode = subgraph.getNode(ModeShapeLexicon.DESCRIPTORS);
241 if (descriptorsNode != null) {
242 for (Location descriptorLocation : descriptorsNode.getChildren()) {
243 Node optionNode = configuration.getNodeAt(descriptorLocation);
244 Path.Segment segment = descriptorLocation.getPath().getLastSegment();
245 Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE);
246 if (valueProperty == null) continue;
247 descriptors.put(segment.getName().getLocalName(), valueProperty.getFirstValue().toString());
248 }
249 }
250
251
252 ExecutionContext context = getExecutionContext();
253 Node namespacesNode = subgraph.getNode(ModeShapeLexicon.NAMESPACES);
254 if (namespacesNode != null) {
255 GraphNamespaceRegistry registry = new GraphNamespaceRegistry(configuration, namespacesNode.getLocation().getPath(),
256 ModeShapeLexicon.NAMESPACE_URI);
257 context = context.with(registry);
258 }
259
260
261 Property property = subgraph.getRoot().getProperty(ModeShapeLexicon.SOURCE_NAME);
262 if (property == null || property.isEmpty()) {
263 String readableName = readable(ModeShapeLexicon.SOURCE_NAME);
264 String readablePath = readable(subgraph.getLocation());
265 String msg = JcrI18n.propertyNotFoundOnNode.text(readableName, readablePath, configuration.getCurrentWorkspaceName());
266 throw new RepositoryException(msg);
267 }
268 String sourceName = context.getValueFactories().getStringFactory().create(property.getFirstValue());
269
270
271 RepositorySource source = getRepositorySource(sourceName);
272 RepositorySourceCapabilities capabilities = source != null ? source.getCapabilities() : null;
273
274 JcrRepository repository = new JcrRepository(context, connectionFactory, sourceName,
275 getRepositoryService().getRepositoryLibrary(), capabilities, descriptors,
276 options);
277
278
279 Node nodeTypesNode = subgraph.getNode(JcrLexicon.NODE_TYPES);
280 if (nodeTypesNode != null) {
281 boolean needToRefreshSubgraph = false;
282
283
284 Property resourceProperty = nodeTypesNode.getProperty(ModeShapeLexicon.RESOURCE);
285 if (resourceProperty != null) {
286 String resources = this.context.getValueFactories().getStringFactory().create(resourceProperty.getFirstValue());
287
288 for (String resource : resources.split("\\s*,\\s*")) {
289 Graph.Batch batch = configuration.batch();
290 GraphBatchDestination destination = new GraphBatchDestination(batch);
291
292 Path nodeTypesPath = pathFactory.create(repositoryPath, JcrLexicon.NODE_TYPES);
293 CndImporter importer = new CndImporter(destination, nodeTypesPath, false);
294 InputStream is = getClass().getResourceAsStream(resource);
295 try {
296 if (is != null) {
297 importer.importFrom(is, this.getProblems(), resource);
298 batch.execute();
299 needToRefreshSubgraph = true;
300 }
301 } catch (IOException ioe) {
302 ioe.printStackTrace();
303 }
304 }
305
306 }
307
308
309 Subgraph nodeTypesSubgraph = subgraph;
310 if (needToRefreshSubgraph) {
311 nodeTypesSubgraph = configuration.getSubgraphOfDepth(4).at(nodeTypesNode.getLocation().getPath());
312 }
313
314 repository.getRepositoryTypeManager().registerNodeTypes(nodeTypesSubgraph, nodeTypesNode.getLocation());
315
316 }
317
318 return repository;
319 }
320
321 protected final String readable( Name name ) {
322 return name.getString(context.getNamespaceRegistry());
323 }
324
325 protected final String readable( Path path ) {
326 return path.getString(context.getNamespaceRegistry());
327 }
328
329 protected final String readable( Location location ) {
330 return location.getString(context.getNamespaceRegistry());
331 }
332 }