1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.modeshape.repository;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.UUID;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Executors;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.concurrent.TimeUnit;
35 import net.jcip.annotations.Immutable;
36 import org.modeshape.common.collection.Problem;
37 import org.modeshape.common.collection.Problems;
38 import org.modeshape.common.collection.SimpleProblems;
39 import org.modeshape.common.util.CheckArg;
40 import org.modeshape.common.util.Logger;
41 import org.modeshape.common.util.NamedThreadFactory;
42 import org.modeshape.graph.ExecutionContext;
43 import org.modeshape.graph.Graph;
44 import org.modeshape.graph.JcrLexicon;
45 import org.modeshape.graph.JcrMixLexicon;
46 import org.modeshape.graph.JcrNtLexicon;
47 import org.modeshape.graph.Location;
48 import org.modeshape.graph.Node;
49 import org.modeshape.graph.Subgraph;
50 import org.modeshape.graph.connector.RepositoryConnectionFactory;
51 import org.modeshape.graph.connector.RepositoryContext;
52 import org.modeshape.graph.connector.RepositorySource;
53 import org.modeshape.graph.connector.RepositorySourceException;
54 import org.modeshape.graph.mimetype.ExtensionBasedMimeTypeDetector;
55 import org.modeshape.graph.mimetype.MimeTypeDetector;
56 import org.modeshape.graph.mimetype.MimeTypeDetectorConfig;
57 import org.modeshape.graph.mimetype.MimeTypeDetectors;
58 import org.modeshape.graph.observe.ObservationBus;
59 import org.modeshape.graph.property.Name;
60 import org.modeshape.graph.property.Path;
61 import org.modeshape.graph.property.PathExpression;
62 import org.modeshape.graph.property.PathNotFoundException;
63 import org.modeshape.graph.property.Property;
64 import org.modeshape.repository.cluster.ClusteringConfig;
65 import org.modeshape.repository.cluster.ClusteringService;
66 import org.modeshape.repository.sequencer.SequencerConfig;
67 import org.modeshape.repository.sequencer.SequencingService;
68
69
70
71
72
73
74
75 @Immutable
76 public class ModeShapeEngine {
77
78 public static final String CONFIGURATION_REPOSITORY_NAME = "dna:configuration";
79 protected static final Logger LOGGER = Logger.getLogger(ModeShapeEngine.class);
80
81 protected final ModeShapeConfiguration.ConfigurationDefinition configuration;
82 private final ConfigurationScanner scanner;
83 private final Problems problems;
84 protected final ExecutionContext context;
85
86 private final RepositoryService repositoryService;
87 private final SequencingService sequencingService;
88 private final ExecutorService executorService;
89 private final ClusteringService clusteringService;
90 private final MimeTypeDetectors detectors;
91 private final String engineId = UUID.randomUUID().toString();
92
93 protected ModeShapeEngine( ExecutionContext context,
94 ModeShapeConfiguration.ConfigurationDefinition configuration ) {
95 this.problems = new SimpleProblems();
96
97
98 this.detectors = new MimeTypeDetectors();
99 this.context = context.with(detectors).with(engineId);
100
101
102 this.configuration = configuration;
103 this.scanner = new ConfigurationScanner(this.problems, this.context, this.configuration);
104
105
106 for (MimeTypeDetectorConfig config : scanner.getMimeTypeDetectors()) {
107 detectors.addDetector(config);
108 }
109
110 detectors.addDetector(new MimeTypeDetectorConfig("ExtensionDetector", "Extension-based MIME type detector",
111 ExtensionBasedMimeTypeDetector.class));
112
113
114 ClusteringConfig clusterConfig = scanner.getClusteringConfiguration();
115 clusteringService = new ClusteringService();
116 clusteringService.setExecutionContext(context);
117 clusteringService.setClusteringConfig(clusterConfig);
118
119
120 Path pathToConfigurationRoot = this.configuration.getPath();
121 String configWorkspaceName = this.configuration.getWorkspace();
122 RepositorySource configSource = this.configuration.getRepositorySource();
123 repositoryService = new RepositoryService(configSource, configWorkspaceName, pathToConfigurationRoot, context,
124 clusteringService, problems);
125
126
127 ThreadFactory threadPoolFactory = new NamedThreadFactory(configuration.getName());
128 executorService = Executors.newCachedThreadPool(threadPoolFactory);
129
130
131 sequencingService = new SequencingService();
132 sequencingService.setExecutionContext(context);
133 sequencingService.setExecutorService(executorService);
134 sequencingService.setRepositoryLibrary(repositoryService.getRepositoryLibrary());
135 for (SequencerConfig sequencerConfig : scanner.getSequencingConfigurations()) {
136 sequencingService.addSequencer(sequencerConfig);
137 }
138
139
140 }
141
142
143
144
145
146
147 public Problems getProblems() {
148 return problems;
149 }
150
151
152
153
154
155
156 public final ExecutionContext getExecutionContext() {
157 return context;
158 }
159
160
161
162
163
164
165
166
167 public final RepositorySource getRepositorySource( String repositoryName ) {
168 checkRunning();
169 return repositoryService.getRepositoryLibrary().getSource(repositoryName);
170 }
171
172
173
174
175
176
177
178 public final RepositoryConnectionFactory getRepositoryConnectionFactory() {
179 checkRunning();
180 return repositoryService.getRepositoryLibrary();
181 }
182
183
184
185
186
187
188
189 public final RepositoryService getRepositoryService() {
190 checkRunning();
191 return repositoryService;
192 }
193
194
195
196
197
198
199
200
201
202
203 public final Graph getGraph( String sourceName ) {
204 CheckArg.isNotNull(sourceName, "sourceName");
205 return getGraph(getExecutionContext(), sourceName);
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219 public final Graph getGraph( ExecutionContext context,
220 String sourceName ) {
221 CheckArg.isNotNull(context, "context");
222 CheckArg.isNotNull(sourceName, "sourceName");
223 checkRunning();
224 Graph graph = Graph.create(sourceName, getRepositoryService().getRepositoryLibrary(), context);
225 if (configuration.getRepositorySource().getName().equals(sourceName) && configuration.getWorkspace() != null) {
226
227 graph.useWorkspace(configuration.getWorkspace());
228 }
229 return graph;
230 }
231
232
233
234
235
236
237
238 public final SequencingService getSequencingService() {
239 checkRunning();
240 return sequencingService;
241 }
242
243
244
245
246
247
248
249 protected final MimeTypeDetector getMimeTypeDetector() {
250 checkRunning();
251 return detectors;
252 }
253
254 protected final boolean checkRunning() {
255 if (repositoryService.getAdministrator().isStarted() && sequencingService.getAdministrator().isStarted()) {
256 return true;
257 }
258 throw new IllegalStateException(RepositoryI18n.engineIsNotRunning.text());
259 }
260
261
262
263
264
265
266
267
268
269
270 public void start() {
271 if (getProblems().hasErrors()) {
272
273 LOGGER.error(RepositoryI18n.errorsPreventStarting);
274 for (Problem problem : getProblems()) {
275 LOGGER.error(problem.getMessage(), problem.getParameters());
276 }
277
278 throw new IllegalStateException(RepositoryI18n.errorsPreventStarting.text());
279 }
280
281
282 RepositoryContext configContext = new SimpleRepositoryContext(context, clusteringService, null);
283 configuration.getRepositorySource().initialize(configContext);
284
285
286 clusteringService.getAdministrator().start();
287 repositoryService.getAdministrator().start();
288 sequencingService.getAdministrator().start();
289
290
291 clusteringService.register(repositoryService);
292 }
293
294
295
296
297
298
299
300
301 public void shutdown() {
302 preShutdown();
303 postShutdown();
304 }
305
306 protected void preShutdown() {
307
308
309 executorService.shutdown();
310
311
312 sequencingService.getAdministrator().shutdown();
313
314
315 repositoryService.getAdministrator().shutdown();
316 }
317
318 protected void postShutdown() {
319
320 clusteringService.shutdown();
321 }
322
323
324
325
326
327
328
329
330
331
332
333 public boolean awaitTermination( long timeout,
334 TimeUnit unit ) throws InterruptedException {
335 if (!sequencingService.getAdministrator().awaitTermination(timeout, unit)) return false;
336 if (!executorService.awaitTermination(timeout, unit)) return false;
337 if (!repositoryService.getAdministrator().awaitTermination(timeout, unit)) return false;
338 return true;
339 }
340
341
342
343
344
345
346 protected Graph getConfigurationGraph() {
347 Graph result = Graph.create(configuration.getRepositorySource(), context);
348 if (configuration.getWorkspace() != null) {
349 result.useWorkspace(configuration.getWorkspace());
350 }
351 return result;
352 }
353
354
355
356
357
358 protected class ConfigurationScanner {
359
360
361
362
363 protected static final String CLUSTERED_OBSERVATION_BUS_CLASSNAME = "org.modeshape.clustering.ClusteredObservationBus";
364
365 private final Problems problems;
366 private final ExecutionContext context;
367 private final ModeShapeConfiguration.ConfigurationDefinition configurationRepository;
368
369 protected ConfigurationScanner( Problems problems,
370 ExecutionContext context,
371 ModeShapeConfiguration.ConfigurationDefinition configurationRepository ) {
372 this.problems = problems;
373 this.context = context;
374 this.configurationRepository = configurationRepository;
375 }
376
377 public List<MimeTypeDetectorConfig> getMimeTypeDetectors() {
378 List<MimeTypeDetectorConfig> detectors = new ArrayList<MimeTypeDetectorConfig>();
379 Graph graph = Graph.create(configurationRepository.getRepositorySource(), context);
380 Path pathToSequencersNode = context.getValueFactories().getPathFactory().create(configurationRepository.getPath(),
381 ModeShapeLexicon.MIME_TYPE_DETECTORS);
382 try {
383 Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToSequencersNode);
384
385 Set<Name> skipProperties = new HashSet<Name>();
386 skipProperties.add(ModeShapeLexicon.READABLE_NAME);
387 skipProperties.add(ModeShapeLexicon.DESCRIPTION);
388 skipProperties.add(ModeShapeLexicon.CLASSNAME);
389 skipProperties.add(ModeShapeLexicon.CLASSPATH);
390 skipProperties.add(ModeShapeLexicon.PATH_EXPRESSION);
391 Set<String> skipNamespaces = new HashSet<String>();
392 skipNamespaces.add(JcrLexicon.Namespace.URI);
393 skipNamespaces.add(JcrNtLexicon.Namespace.URI);
394 skipNamespaces.add(JcrMixLexicon.Namespace.URI);
395
396 for (Location detectorLocation : subgraph.getRoot().getChildren()) {
397 Node node = subgraph.getNode(detectorLocation);
398 String name = stringValueOf(node, ModeShapeLexicon.READABLE_NAME);
399 if (name == null) name = stringValueOf(node);
400 String desc = stringValueOf(node, ModeShapeLexicon.DESCRIPTION);
401 String classname = stringValueOf(node, ModeShapeLexicon.CLASSNAME);
402 String[] classpath = stringValuesOf(node, ModeShapeLexicon.CLASSPATH);
403 Map<String, Object> properties = new HashMap<String, Object>();
404 for (Property property : node.getProperties()) {
405 Name propertyName = property.getName();
406 if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
407 if (skipProperties.contains(propertyName)) continue;
408 if (property.isSingle()) {
409 properties.put(propertyName.getLocalName(), property.getFirstValue());
410 } else {
411 properties.put(propertyName.getLocalName(), property.getValuesAsArray());
412 }
413 }
414 MimeTypeDetectorConfig config = new MimeTypeDetectorConfig(name, desc, properties, classname, classpath);
415 detectors.add(config);
416 }
417 } catch (PathNotFoundException e) {
418
419 }
420 return detectors;
421 }
422
423 public ClusteringConfig getClusteringConfiguration() {
424 Graph graph = Graph.create(configurationRepository.getRepositorySource(), context);
425 Path pathToClusteringNode = context.getValueFactories().getPathFactory().create(configurationRepository.getPath(),
426 ModeShapeLexicon.CLUSTERING);
427 try {
428 Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToClusteringNode);
429
430 Set<Name> skipProperties = new HashSet<Name>();
431 skipProperties.add(ModeShapeLexicon.DESCRIPTION);
432 skipProperties.add(ModeShapeLexicon.CLASSNAME);
433 skipProperties.add(ModeShapeLexicon.CLASSPATH);
434 Set<String> skipNamespaces = new HashSet<String>();
435 skipNamespaces.add(JcrLexicon.Namespace.URI);
436 skipNamespaces.add(JcrNtLexicon.Namespace.URI);
437 skipNamespaces.add(JcrMixLexicon.Namespace.URI);
438
439 Node clusterNode = subgraph.getRoot();
440
441 String clusterName = stringValueOf(clusterNode, ModeShapeLexicon.CLUSTER_NAME);
442 String desc = stringValueOf(clusterNode, ModeShapeLexicon.DESCRIPTION);
443 String classname = stringValueOf(clusterNode, ModeShapeLexicon.CLASSNAME);
444 String[] classpath = stringValuesOf(clusterNode, ModeShapeLexicon.CLASSPATH);
445 if (classname == null || classname.trim().length() == 0) {
446 classname = CLUSTERED_OBSERVATION_BUS_CLASSNAME;
447 }
448 if (clusterName == null || clusterName.trim().length() == 0) {
449 LOGGER.warn(RepositoryI18n.clusteringConfigurationRequiresClusterName);
450 problems.addWarning(RepositoryI18n.clusteringConfigurationRequiresClusterName);
451 return null;
452 }
453
454 Map<String, Object> properties = new HashMap<String, Object>();
455 for (Property property : clusterNode.getProperties()) {
456 Name propertyName = property.getName();
457 if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
458 if (skipProperties.contains(propertyName)) continue;
459 if (property.isSingle()) {
460 properties.put(propertyName.getLocalName(), property.getFirstValue());
461 } else {
462 properties.put(propertyName.getLocalName(), property.getValuesAsArray());
463 }
464 }
465 return new ClusteringConfig(clusterName, desc, properties, classname, classpath);
466 } catch (PathNotFoundException e) {
467
468 }
469 return null;
470 }
471
472 public List<SequencerConfig> getSequencingConfigurations() {
473 List<SequencerConfig> configs = new ArrayList<SequencerConfig>();
474 Graph graph = Graph.create(configurationRepository.getRepositorySource(), context);
475 Path pathToSequencersNode = context.getValueFactories().getPathFactory().create(configurationRepository.getPath(),
476 ModeShapeLexicon.SEQUENCERS);
477 try {
478 Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToSequencersNode);
479
480 Set<Name> skipProperties = new HashSet<Name>();
481 skipProperties.add(ModeShapeLexicon.READABLE_NAME);
482 skipProperties.add(ModeShapeLexicon.DESCRIPTION);
483 skipProperties.add(ModeShapeLexicon.CLASSNAME);
484 skipProperties.add(ModeShapeLexicon.CLASSPATH);
485 skipProperties.add(ModeShapeLexicon.PATH_EXPRESSION);
486 Set<String> skipNamespaces = new HashSet<String>();
487 skipNamespaces.add(JcrLexicon.Namespace.URI);
488 skipNamespaces.add(JcrNtLexicon.Namespace.URI);
489 skipNamespaces.add(JcrMixLexicon.Namespace.URI);
490
491 for (Location sequencerLocation : subgraph.getRoot().getChildren()) {
492 Node sequencerNode = subgraph.getNode(sequencerLocation);
493 String name = stringValueOf(sequencerNode, ModeShapeLexicon.READABLE_NAME);
494 if (name == null) name = stringValueOf(sequencerNode);
495 String desc = stringValueOf(sequencerNode, ModeShapeLexicon.DESCRIPTION);
496 String classname = stringValueOf(sequencerNode, ModeShapeLexicon.CLASSNAME);
497 String[] classpath = stringValuesOf(sequencerNode, ModeShapeLexicon.CLASSPATH);
498 String[] expressionStrings = stringValuesOf(sequencerNode, ModeShapeLexicon.PATH_EXPRESSION);
499 List<PathExpression> pathExpressions = new ArrayList<PathExpression>();
500 if (expressionStrings != null) {
501 for (String expressionString : expressionStrings) {
502 try {
503 pathExpressions.add(PathExpression.compile(expressionString));
504 } catch (Throwable t) {
505 problems.addError(t,
506 RepositoryI18n.pathExpressionIsInvalidOnSequencer,
507 expressionString,
508 name,
509 t.getLocalizedMessage());
510 }
511 }
512 }
513 String[] goodExpressionStrings = new String[pathExpressions.size()];
514 for (int i = 0; i != pathExpressions.size(); ++i) {
515 PathExpression expression = pathExpressions.get(i);
516 goodExpressionStrings[i] = expression.getExpression();
517 }
518 Map<String, Object> properties = new HashMap<String, Object>();
519 for (Property property : sequencerNode.getProperties()) {
520 Name propertyName = property.getName();
521 if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
522 if (skipProperties.contains(propertyName)) continue;
523 if (property.isSingle()) {
524 properties.put(propertyName.getLocalName(), property.getFirstValue());
525 } else {
526 properties.put(propertyName.getLocalName(), property.getValuesAsArray());
527 }
528 }
529 SequencerConfig config = new SequencerConfig(name, desc, properties, classname, classpath,
530 goodExpressionStrings);
531 configs.add(config);
532 }
533 } catch (PathNotFoundException e) {
534
535 }
536 return configs;
537 }
538
539 private String stringValueOf( Node node ) {
540 return node.getLocation().getPath().getLastSegment().getString(context.getNamespaceRegistry());
541 }
542
543 private String stringValueOf( Node node,
544 Name propertyName ) {
545 Property property = node.getProperty(propertyName);
546 if (property == null) {
547
548 property = node.getProperty(context.getValueFactories().getNameFactory().create(propertyName.getLocalName()));
549 if (property == null) return null;
550 }
551 if (property.isEmpty()) return null;
552 return context.getValueFactories().getStringFactory().create(property.getFirstValue());
553 }
554
555 private String[] stringValuesOf( Node node,
556 Name propertyName ) {
557 Property property = node.getProperty(propertyName);
558 if (property == null) {
559
560 property = node.getProperty(context.getValueFactories().getNameFactory().create(propertyName.getLocalName()));
561 if (property == null) return null;
562 }
563 return context.getValueFactories().getStringFactory().create(property.getValuesAsArray());
564 }
565
566 }
567 }