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.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.net.URL;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import javax.jcr.PropertyType;
38 import javax.jcr.Session;
39 import javax.jcr.Value;
40 import javax.jcr.nodetype.ConstraintViolationException;
41 import javax.jcr.nodetype.NodeDefinitionTemplate;
42 import javax.jcr.nodetype.NodeTypeDefinition;
43 import javax.jcr.nodetype.NodeTypeTemplate;
44 import javax.jcr.nodetype.PropertyDefinitionTemplate;
45 import javax.jcr.version.OnParentVersionAction;
46 import net.jcip.annotations.NotThreadSafe;
47 import org.modeshape.common.collection.Problems;
48 import org.modeshape.common.collection.SimpleProblems;
49 import org.modeshape.common.util.CheckArg;
50 import org.modeshape.common.util.IoUtil;
51 import org.modeshape.graph.ExecutionContext;
52 import org.modeshape.graph.Graph;
53 import org.modeshape.graph.Location;
54 import org.modeshape.graph.Subgraph;
55 import org.modeshape.graph.SubgraphNode;
56 import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource;
57 import org.modeshape.graph.io.Destination;
58 import org.modeshape.graph.io.GraphBatchDestination;
59 import org.modeshape.graph.property.Name;
60 import org.modeshape.graph.property.NameFactory;
61 import org.modeshape.graph.property.Path;
62 import org.modeshape.graph.property.PathFactory;
63 import org.modeshape.graph.property.Property;
64 import org.modeshape.graph.property.ValueFactories;
65 import org.modeshape.graph.property.ValueFactory;
66 import org.modeshape.graph.property.basic.LocalNamespaceRegistry;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 @NotThreadSafe
109 class GraphNodeTypeReader implements Iterable<NodeTypeDefinition> {
110
111 private static final Map<String, Integer> PROPERTY_TYPE_VALUES_FROM_NAME;
112
113 static {
114 Map<String, Integer> temp = new HashMap<String, Integer>();
115
116 temp.put(PropertyType.TYPENAME_BINARY.toUpperCase(), PropertyType.BINARY);
117 temp.put(PropertyType.TYPENAME_BOOLEAN.toUpperCase(), PropertyType.BOOLEAN);
118 temp.put(PropertyType.TYPENAME_DATE.toUpperCase(), PropertyType.DATE);
119 temp.put(PropertyType.TYPENAME_DECIMAL.toUpperCase(), PropertyType.DECIMAL);
120 temp.put(PropertyType.TYPENAME_DOUBLE.toUpperCase(), PropertyType.DOUBLE);
121 temp.put(PropertyType.TYPENAME_LONG.toUpperCase(), PropertyType.LONG);
122 temp.put(PropertyType.TYPENAME_NAME.toUpperCase(), PropertyType.NAME);
123 temp.put(PropertyType.TYPENAME_PATH.toUpperCase(), PropertyType.PATH);
124 temp.put(PropertyType.TYPENAME_STRING.toUpperCase(), PropertyType.STRING);
125 temp.put(PropertyType.TYPENAME_REFERENCE.toUpperCase(), PropertyType.REFERENCE);
126 temp.put(PropertyType.TYPENAME_WEAKREFERENCE.toUpperCase(), PropertyType.WEAKREFERENCE);
127 temp.put(PropertyType.TYPENAME_UNDEFINED.toUpperCase(), PropertyType.UNDEFINED);
128 temp.put(PropertyType.TYPENAME_URI.toUpperCase(), PropertyType.URI);
129
130 PROPERTY_TYPE_VALUES_FROM_NAME = Collections.unmodifiableMap(temp);
131 }
132
133 protected final Problems problems = new SimpleProblems();
134 protected final List<NodeTypeDefinition> types = new ArrayList<NodeTypeDefinition>();
135 protected final List<NodeTypeDefinition> immutableTypes = Collections.unmodifiableList(types);
136 protected final ExecutionContext context;
137 protected final ValueFactories valueFactories;
138 protected final PathFactory pathFactory;
139 protected final NameFactory nameFactory;
140 protected final ValueFactory<Boolean> booleanFactory;
141 protected final ValueFactory<String> stringFactory;
142 protected final Path root;
143
144
145
146
147
148
149 protected GraphNodeTypeReader( Session session ) {
150 this(CheckArg.getInstanceOf(session, JcrSession.class, "session").getExecutionContext());
151 }
152
153
154
155
156
157
158
159 protected GraphNodeTypeReader( ExecutionContext executionContext ) {
160 LocalNamespaceRegistry localRegistry = new LocalNamespaceRegistry(executionContext.getNamespaceRegistry());
161 context = executionContext.with(localRegistry);
162 valueFactories = context.getValueFactories();
163 pathFactory = valueFactories.getPathFactory();
164 nameFactory = valueFactories.getNameFactory();
165 booleanFactory = valueFactories.getBooleanFactory();
166 stringFactory = valueFactories.getStringFactory();
167 root = pathFactory.createRootPath();
168 }
169
170
171
172
173
174
175
176
177
178
179 public void read( InputStream stream,
180 String resourceName ) throws IOException {
181 read(IoUtil.read(stream), resourceName);
182 }
183
184
185
186
187
188
189
190
191 public void read( File file ) throws IOException {
192 CheckArg.isNotNull(file, "file");
193 if (!file.exists() || !file.canRead()) {
194 throw new IOException(JcrI18n.fileMustExistAndBeReadable.text(file.getCanonicalPath()));
195 }
196 read(IoUtil.read(file), file.getCanonicalPath());
197 }
198
199
200
201
202
203
204
205
206 public void read( URL url ) throws IOException {
207 CheckArg.isNotNull(url, "url");
208 InputStream stream = url.openStream();
209 boolean error = false;
210 try {
211 read(IoUtil.read(stream), url.toString());
212 } catch (IOException e) {
213 error = true;
214 throw e;
215 } catch (RuntimeException e) {
216 error = true;
217 throw e;
218 } finally {
219 try {
220 stream.close();
221 } catch (IOException e) {
222 if (!error) throw e;
223 } catch (RuntimeException e) {
224 if (!error) throw e;
225 }
226 }
227 }
228
229
230
231
232
233
234
235
236
237
238
239 public void read( String resourceFile ) throws IOException {
240 CheckArg.isNotEmpty(resourceFile, "resourceFile");
241 ClassLoader classLoader = context.getClassLoader();
242 InputStream stream = IoUtil.getResourceAsStream(resourceFile, classLoader, getClass());
243 if (stream == null) {
244 throw new IOException(JcrI18n.unableToFindResourceOnClasspathOrFileOrUrl.text(resourceFile));
245 }
246 boolean error = false;
247 try {
248 read(IoUtil.read(stream), resourceFile);
249 } catch (IOException e) {
250 error = true;
251 throw e;
252 } catch (RuntimeException e) {
253 error = true;
254 throw e;
255 } finally {
256 try {
257 stream.close();
258 } catch (IOException e) {
259 if (!error) throw e;
260 } catch (RuntimeException e) {
261 if (!error) throw e;
262 }
263 }
264 }
265
266
267
268
269
270
271
272
273 @SuppressWarnings( "cast" )
274 public void read( String content,
275 String resourceName ) {
276 InMemoryRepositorySource source = new InMemoryRepositorySource();
277 source.setName("Node Type Import Source");
278 Graph graph = Graph.create(source, context);
279
280
281 Graph.Batch batch = graph.batch();
282 Destination destination = new GraphBatchDestination(batch);
283 try {
284 importFrom(destination, root, content, resourceName);
285 List<NodeTypeDefinition> types = readTypesFrom(graph, root, null);
286 this.types.addAll(types);
287 } catch (Throwable t) {
288 problems.addError(t, JcrI18n.errorImportingNodeTypeContent, (Object)resourceName, t.getMessage());
289 }
290 }
291
292
293
294
295
296
297
298
299
300 public void read( Graph graph,
301 Path parentOfTypes,
302 String resourceName ) {
303 this.types.addAll(readTypesFrom(graph, parentOfTypes, null));
304 }
305
306
307
308
309
310
311
312
313
314
315 public void read( Graph graph,
316 Path parentOfTypes,
317 Collection<Name> nodeTypesToRead,
318 String resourceName ) {
319 this.types.addAll(readTypesFrom(graph, parentOfTypes, nodeTypesToRead));
320 }
321
322
323
324
325
326
327
328
329
330 public void read( Subgraph subgraph,
331 Location locationOfParent,
332 String resourceName ) {
333 this.types.addAll(readTypesFrom(subgraph, locationOfParent, null));
334 }
335
336
337
338
339
340
341 public Problems getProblems() {
342 return problems;
343 }
344
345
346
347
348
349
350 public NodeTypeDefinition[] getNodeTypeDefinitions() {
351 return types.toArray(new NodeTypeDefinition[types.size()]);
352 }
353
354
355
356
357
358
359 @Override
360 public Iterator<NodeTypeDefinition> iterator() {
361 return immutableTypes.iterator();
362 }
363
364 protected List<NodeTypeDefinition> readTypesFrom( Graph graph,
365 Path parentOfTypes,
366 Collection<Name> nodeTypesToRead ) {
367 Subgraph subgraph = graph.getSubgraphOfDepth(5).at(parentOfTypes);
368 return readTypesFrom(subgraph, subgraph.getLocation(), nodeTypesToRead);
369 }
370
371 protected List<NodeTypeDefinition> readTypesFrom( Subgraph nodeTypeSubgraph,
372 Location locationOfParentOfNodeTypes,
373 Collection<Name> nodeTypesToRead ) {
374 List<Location> nodeTypeLocations = nodeTypeSubgraph.getNode(locationOfParentOfNodeTypes).getChildren();
375 List<NodeTypeDefinition> results = new ArrayList<NodeTypeDefinition>(nodeTypeLocations.size());
376 boolean shouldFilterNodes = locationOfParentOfNodeTypes.hasPath() && nodeTypesToRead != null;
377
378 for (Location location : nodeTypeLocations) {
379 SubgraphNode nodeTypeNode = nodeTypeSubgraph.getNode(location);
380 assert location.getPath() != null;
381
382 Path relativeNodeTypePath = shouldFilterNodes ? location.getPath().relativeTo(locationOfParentOfNodeTypes.getPath()) : null;
383 if (shouldFilterNodes && !nodeTypesToRead.contains(relativeNodeTypePath.getSegment(0).getName())) {
384 continue;
385 }
386
387 try {
388 NodeTypeDefinition nodeType = nodeTypeFrom(nodeTypeNode, nodeTypeSubgraph);
389 results.add(nodeType);
390 } catch (ConstraintViolationException e) {
391 String resource = stringFactory.create(locationOfParentOfNodeTypes.getPath());
392 problems.addError(e, JcrI18n.errorImportingNodeTypeContent, resource, e.getMessage());
393 }
394 }
395 return results;
396 }
397
398 @SuppressWarnings( "unchecked" )
399 protected NodeTypeTemplate nodeTypeFrom( SubgraphNode nodeTypeNode,
400 Subgraph subgraph ) throws ConstraintViolationException {
401 List<Location> children = nodeTypeNode.getChildren();
402
403 String name = readString(nodeTypeNode, JcrLexicon.NODE_TYPE_NAME, null);
404 String primaryItemName = readString(nodeTypeNode, JcrLexicon.PRIMARY_ITEM_NAME, null);
405
406 boolean mixin = readBoolean(nodeTypeNode, JcrLexicon.IS_MIXIN, false);
407 boolean isAbstract = readBoolean(nodeTypeNode, JcrLexicon.IS_ABSTRACT, false);
408 boolean queryable = readBoolean(nodeTypeNode, JcrLexicon.IS_QUERYABLE, true);
409 boolean orderableChildNodes = readBoolean(nodeTypeNode, JcrLexicon.HAS_ORDERABLE_CHILD_NODES, false);
410 List<String> supertypes = readStrings(nodeTypeNode, JcrLexicon.SUPERTYPES);
411
412 NodeTypeTemplate template = new JcrNodeTypeTemplate(context);
413 template.setAbstract(isAbstract);
414 template.setDeclaredSuperTypeNames(supertypes.toArray(new String[supertypes.size()]));
415 template.setMixin(mixin);
416 template.setName(name);
417 template.setOrderableChildNodes(orderableChildNodes);
418 template.setPrimaryItemName(primaryItemName);
419 template.setQueryable(queryable);
420
421 for (Location childLocation : children) {
422 if (JcrLexicon.PROPERTY_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) {
423 template.getPropertyDefinitionTemplates().add(propertyDefinitionFrom(subgraph, childLocation));
424 } else if (JcrLexicon.CHILD_NODE_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) {
425 template.getNodeDefinitionTemplates().add(childNodeDefinitionFrom(subgraph, childLocation));
426 } else {
427 throw new IllegalStateException("Unexpected child of node type at: " + childLocation);
428 }
429 }
430
431 return template;
432 }
433
434 protected PropertyDefinitionTemplate propertyDefinitionFrom( Subgraph nodeTypeGraph,
435 Location propertyLocation ) throws ConstraintViolationException {
436 SubgraphNode propertyDefinitionNode = nodeTypeGraph.getNode(propertyLocation);
437
438 String name = readString(propertyDefinitionNode, JcrLexicon.NAME, null);
439 String onParentVersionName = readString(propertyDefinitionNode,
440 JcrLexicon.ON_PARENT_VERSION,
441 OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY));
442 int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName);
443
444 int requiredType = PROPERTY_TYPE_VALUES_FROM_NAME.get(readString(propertyDefinitionNode, JcrLexicon.REQUIRED_TYPE, null));
445
446 boolean mandatory = readBoolean(propertyDefinitionNode, JcrLexicon.MANDATORY, false);
447 boolean multiple = readBoolean(propertyDefinitionNode, JcrLexicon.MULTIPLE, false);
448 boolean autoCreated = readBoolean(propertyDefinitionNode, JcrLexicon.AUTO_CREATED, false);
449 boolean isProtected = readBoolean(propertyDefinitionNode, JcrLexicon.PROTECTED, false);
450 boolean isSearchable = readBoolean(propertyDefinitionNode, JcrLexicon.IS_FULL_TEXT_SEARCHABLE, true);
451 boolean isOrderable = readBoolean(propertyDefinitionNode, JcrLexicon.IS_QUERY_ORDERABLE, true);
452 List<Value> defaultValues = readValues(propertyDefinitionNode, JcrLexicon.DEFAULT_VALUES, requiredType);
453 List<String> constraints = readStrings(propertyDefinitionNode, JcrLexicon.VALUE_CONSTRAINTS);
454 List<String> queryOps = readStrings(propertyDefinitionNode, JcrLexicon.QUERY_OPERATORS);
455
456 PropertyDefinitionTemplate template = new JcrPropertyDefinitionTemplate(context);
457 if (name != null) {
458 template.setName(name);
459 }
460 template.setAutoCreated(autoCreated);
461 template.setMandatory(mandatory);
462 template.setMultiple(multiple);
463 template.setProtected(isProtected);
464 template.setFullTextSearchable(isSearchable);
465 template.setAvailableQueryOperators(queryOps.toArray(new String[queryOps.size()]));
466 template.setQueryOrderable(isOrderable);
467 template.setProtected(isProtected);
468 template.setOnParentVersion(onParentVersion);
469 template.setDefaultValues(defaultValues.toArray(new Value[defaultValues.size()]));
470 template.setRequiredType(requiredType);
471 template.setValueConstraints(constraints.toArray(new String[constraints.size()]));
472 return template;
473 }
474
475 protected NodeDefinitionTemplate childNodeDefinitionFrom( Subgraph nodeTypeGraph,
476 Location childNodeLocation ) throws ConstraintViolationException {
477 SubgraphNode childNodeDefinitionNode = nodeTypeGraph.getNode(childNodeLocation);
478
479 String childNodeName = readString(childNodeDefinitionNode, JcrLexicon.NAME, null);
480 String defaultPrimaryTypeName = readString(childNodeDefinitionNode, JcrLexicon.DEFAULT_PRIMARY_TYPE, null);
481 String onParentVersionName = readString(childNodeDefinitionNode,
482 JcrLexicon.ON_PARENT_VERSION,
483 OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY));
484 int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName);
485
486 boolean mandatory = readBoolean(childNodeDefinitionNode, JcrLexicon.MANDATORY, false);
487 boolean allowsSns = readBoolean(childNodeDefinitionNode, JcrLexicon.SAME_NAME_SIBLINGS, false);
488 boolean autoCreated = readBoolean(childNodeDefinitionNode, JcrLexicon.AUTO_CREATED, false);
489 boolean isProtected = readBoolean(childNodeDefinitionNode, JcrLexicon.PROTECTED, false);
490 List<String> requiredTypes = readStrings(childNodeDefinitionNode, JcrLexicon.REQUIRED_PRIMARY_TYPES);
491
492 NodeDefinitionTemplate template = new JcrNodeDefinitionTemplate(context);
493 if (childNodeName != null) {
494 template.setName(childNodeName);
495 }
496 template.setAutoCreated(autoCreated);
497 template.setMandatory(mandatory);
498 template.setSameNameSiblings(allowsSns);
499 template.setProtected(isProtected);
500 template.setOnParentVersion(onParentVersion);
501 template.setDefaultPrimaryTypeName(defaultPrimaryTypeName);
502 template.setRequiredPrimaryTypeNames(requiredTypes.toArray(new String[requiredTypes.size()]));
503 return template;
504 }
505
506 protected Name nameFrom( SubgraphNode node ) {
507 return node.getLocation().getPath().getLastSegment().getName();
508 }
509
510 protected Name name( String name ) {
511 return nameFactory.create(name);
512 }
513
514 protected String string( Object value ) {
515 return stringFactory.create(value);
516 }
517
518 protected boolean readBoolean( SubgraphNode node,
519 String propertyName,
520 boolean defaultValue ) {
521 return readBoolean(node, nameFactory.create(propertyName), defaultValue);
522 }
523
524 protected boolean readBoolean( SubgraphNode node,
525 Name propertyName,
526 boolean defaultValue ) {
527 Property property = node.getProperty(propertyName);
528 return property != null ? booleanFactory.create(property.getFirstValue()) : defaultValue;
529 }
530
531 protected String readString( SubgraphNode node,
532 String propertyName,
533 String defaultValue ) {
534 return readString(node, nameFactory.create(propertyName), defaultValue);
535 }
536
537 protected String readString( SubgraphNode node,
538 Name propertyName,
539 String defaultValue ) {
540 Property property = node.getProperty(propertyName);
541 return property != null ? stringFactory.create(property.getFirstValue()) : defaultValue;
542 }
543
544 protected List<String> readStrings( SubgraphNode node,
545 String propertyName ) {
546 return readStrings(node, nameFactory.create(propertyName));
547 }
548
549 protected List<String> readStrings( SubgraphNode node,
550 Name propertyName ) {
551 List<String> results = new ArrayList<String>();
552 Property property = node.getProperty(propertyName);
553 if (property != null) {
554 for (Object value : property) {
555 String str = stringFactory.create(value);
556 if (str != null && str.length() != 0) results.add(str);
557 }
558 }
559 return results;
560 }
561
562 protected List<Value> readValues( SubgraphNode node,
563 Name propertyName,
564 int requiredType ) {
565 List<String> results = readStrings(node, propertyName);
566 List<Value> values = new ArrayList<Value>(results.size());
567 for (String result : results) {
568 values.add(new JcrValue(valueFactories, null, requiredType, result));
569 }
570 return values;
571 }
572
573 protected Name readName( SubgraphNode node,
574 String propertyName,
575 Name defaultValue ) {
576 return readName(node, nameFactory.create(propertyName), defaultValue);
577 }
578
579 protected Name readName( SubgraphNode node,
580 Name propertyName,
581 Name defaultValue ) {
582 Property property = node.getProperty(propertyName);
583 if (property != null && !property.isEmpty()) {
584 String firstValue = stringFactory.create(property.getFirstValue());
585 if (firstValue != null && firstValue.trim().length() != 0) {
586 return valueFactories.getNameFactory().create(firstValue);
587 }
588 }
589 return defaultValue;
590 }
591
592 protected List<Name> readNames( SubgraphNode node,
593 String propertyName,
594 Name defaultIfNone ) {
595 return readNames(node, nameFactory.create(propertyName), defaultIfNone);
596 }
597
598 protected List<Name> readNames( SubgraphNode node,
599 Name propertyName,
600 Name defaultIfNone ) {
601 List<Name> results = new ArrayList<Name>();
602 Property property = node.getProperty(propertyName);
603 if (property != null) {
604 for (Object value : property) {
605 Name name = nameFactory.create(value);
606 if (name != null) results.add(name);
607 }
608 }
609 if (results.isEmpty() && defaultIfNone != null) results.add(defaultIfNone);
610 return results;
611 }
612
613
614
615
616
617
618
619
620
621
622 protected void importFrom( Destination graphDestination,
623 Path path,
624 String content,
625 String resourceName ) throws Exception {
626 throw new UnsupportedOperationException();
627 }
628
629 }