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 public void read( InputStream stream,
179 String resourceName ) throws IOException {
180 read(IoUtil.read(stream), resourceName);
181 }
182
183
184
185
186
187
188
189 public void read( File file ) throws IOException {
190 read(IoUtil.read(file), file.getCanonicalPath());
191 }
192
193
194
195
196
197
198
199 public void read( URL url ) throws IOException {
200 InputStream stream = url.openStream();
201 try {
202 read(IoUtil.read(stream), url.toString());
203 } finally {
204 stream.close();
205 }
206 }
207
208
209
210
211
212
213
214 public void read( String resourceFile ) throws IOException {
215 InputStream stream = getClass().getResourceAsStream(resourceFile);
216 if (stream != null) {
217 try {
218 read(IoUtil.read(stream), resourceFile);
219 } finally {
220 stream.close();
221 }
222 }
223 }
224
225
226
227
228
229
230
231
232 @SuppressWarnings( "cast" )
233 public void read( String content,
234 String resourceName ) {
235 InMemoryRepositorySource source = new InMemoryRepositorySource();
236 source.setName("Node Type Import Source");
237 Graph graph = Graph.create(source, context);
238
239
240 Graph.Batch batch = graph.batch();
241 Destination destination = new GraphBatchDestination(batch);
242 try {
243 importFrom(destination, root, content, resourceName);
244 List<NodeTypeDefinition> types = readTypesFrom(graph, root, null);
245 this.types.addAll(types);
246 } catch (Throwable t) {
247 problems.addError(t, JcrI18n.errorImportingNodeTypeContent, (Object)resourceName, t.getMessage());
248 }
249 }
250
251
252
253
254
255
256
257
258
259 public void read( Graph graph,
260 Path parentOfTypes,
261 String resourceName ) {
262 this.types.addAll(readTypesFrom(graph, parentOfTypes, null));
263 }
264
265
266
267
268
269
270
271
272
273
274 public void read( Graph graph,
275 Path parentOfTypes,
276 Collection<Name> nodeTypesToRead,
277 String resourceName ) {
278 this.types.addAll(readTypesFrom(graph, parentOfTypes, nodeTypesToRead));
279 }
280
281
282
283
284
285
286
287
288
289 public void read( Subgraph subgraph,
290 Location locationOfParent,
291 String resourceName ) {
292 this.types.addAll(readTypesFrom(subgraph, locationOfParent, null));
293 }
294
295
296
297
298
299
300 public Problems getProblems() {
301 return problems;
302 }
303
304
305
306
307
308
309 public NodeTypeDefinition[] getNodeTypeDefinitions() {
310 return types.toArray(new NodeTypeDefinition[types.size()]);
311 }
312
313
314
315
316
317
318 @Override
319 public Iterator<NodeTypeDefinition> iterator() {
320 return immutableTypes.iterator();
321 }
322
323 protected List<NodeTypeDefinition> readTypesFrom( Graph graph,
324 Path parentOfTypes,
325 Collection<Name> nodeTypesToRead ) {
326 Subgraph subgraph = graph.getSubgraphOfDepth(5).at(parentOfTypes);
327 return readTypesFrom(subgraph, subgraph.getLocation(), nodeTypesToRead);
328 }
329
330 protected List<NodeTypeDefinition> readTypesFrom( Subgraph nodeTypeSubgraph,
331 Location locationOfParentOfNodeTypes,
332 Collection<Name> nodeTypesToRead ) {
333 List<Location> nodeTypeLocations = nodeTypeSubgraph.getNode(locationOfParentOfNodeTypes).getChildren();
334 List<NodeTypeDefinition> results = new ArrayList<NodeTypeDefinition>(nodeTypeLocations.size());
335 boolean shouldFilterNodes = locationOfParentOfNodeTypes.hasPath() && nodeTypesToRead != null;
336
337 for (Location location : nodeTypeLocations) {
338 SubgraphNode nodeTypeNode = nodeTypeSubgraph.getNode(location);
339 assert location.getPath() != null;
340
341 Path relativeNodeTypePath = shouldFilterNodes ? location.getPath().relativeTo(locationOfParentOfNodeTypes.getPath()) : null;
342 if (shouldFilterNodes && !nodeTypesToRead.contains(relativeNodeTypePath.getSegment(0).getName())) {
343 continue;
344 }
345
346 try {
347 NodeTypeDefinition nodeType = nodeTypeFrom(nodeTypeNode, nodeTypeSubgraph);
348 results.add(nodeType);
349 } catch (ConstraintViolationException e) {
350 String resource = stringFactory.create(locationOfParentOfNodeTypes.getPath());
351 problems.addError(e, JcrI18n.errorImportingNodeTypeContent, resource, e.getMessage());
352 }
353 }
354 return results;
355 }
356
357 @SuppressWarnings( "unchecked" )
358 protected NodeTypeTemplate nodeTypeFrom( SubgraphNode nodeTypeNode,
359 Subgraph subgraph ) throws ConstraintViolationException {
360 List<Location> children = nodeTypeNode.getChildren();
361
362 String name = readString(nodeTypeNode, JcrLexicon.NODE_TYPE_NAME, null);
363 String primaryItemName = readString(nodeTypeNode, JcrLexicon.PRIMARY_ITEM_NAME, null);
364
365 boolean mixin = readBoolean(nodeTypeNode, JcrLexicon.IS_MIXIN, false);
366 boolean isAbstract = readBoolean(nodeTypeNode, JcrLexicon.IS_ABSTRACT, false);
367 boolean queryable = readBoolean(nodeTypeNode, JcrLexicon.IS_QUERYABLE, true);
368 boolean orderableChildNodes = readBoolean(nodeTypeNode, JcrLexicon.HAS_ORDERABLE_CHILD_NODES, false);
369 List<String> supertypes = readStrings(nodeTypeNode, JcrLexicon.SUPERTYPES);
370
371 NodeTypeTemplate template = new JcrNodeTypeTemplate(context);
372 template.setAbstract(isAbstract);
373 template.setDeclaredSuperTypeNames(supertypes.toArray(new String[supertypes.size()]));
374 template.setMixin(mixin);
375 template.setName(name);
376 template.setOrderableChildNodes(orderableChildNodes);
377 template.setPrimaryItemName(primaryItemName);
378 template.setQueryable(queryable);
379
380 for (Location childLocation : children) {
381 if (JcrLexicon.PROPERTY_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) {
382 template.getPropertyDefinitionTemplates().add(propertyDefinitionFrom(subgraph, childLocation));
383 } else if (JcrLexicon.CHILD_NODE_DEFINITION.equals(childLocation.getPath().getLastSegment().getName())) {
384 template.getNodeDefinitionTemplates().add(childNodeDefinitionFrom(subgraph, childLocation));
385 } else {
386 throw new IllegalStateException("Unexpected child of node type at: " + childLocation);
387 }
388 }
389
390 return template;
391 }
392
393 protected PropertyDefinitionTemplate propertyDefinitionFrom( Subgraph nodeTypeGraph,
394 Location propertyLocation ) throws ConstraintViolationException {
395 SubgraphNode propertyDefinitionNode = nodeTypeGraph.getNode(propertyLocation);
396
397 String name = readString(propertyDefinitionNode, JcrLexicon.NAME, null);
398 String onParentVersionName = readString(propertyDefinitionNode,
399 JcrLexicon.ON_PARENT_VERSION,
400 OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY));
401 int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName);
402
403 int requiredType = PROPERTY_TYPE_VALUES_FROM_NAME.get(readString(propertyDefinitionNode, JcrLexicon.REQUIRED_TYPE, null));
404
405 boolean mandatory = readBoolean(propertyDefinitionNode, JcrLexicon.MANDATORY, false);
406 boolean multiple = readBoolean(propertyDefinitionNode, JcrLexicon.MULTIPLE, false);
407 boolean autoCreated = readBoolean(propertyDefinitionNode, JcrLexicon.AUTO_CREATED, false);
408 boolean isProtected = readBoolean(propertyDefinitionNode, JcrLexicon.PROTECTED, false);
409 boolean isSearchable = readBoolean(propertyDefinitionNode, JcrLexicon.IS_FULL_TEXT_SEARCHABLE, true);
410 boolean isOrderable = readBoolean(propertyDefinitionNode, JcrLexicon.IS_QUERY_ORDERABLE, true);
411 List<Value> defaultValues = readValues(propertyDefinitionNode, JcrLexicon.DEFAULT_VALUES, requiredType);
412 List<String> constraints = readStrings(propertyDefinitionNode, JcrLexicon.VALUE_CONSTRAINTS);
413 List<String> queryOps = readStrings(propertyDefinitionNode, JcrLexicon.QUERY_OPERATORS);
414
415 PropertyDefinitionTemplate template = new JcrPropertyDefinitionTemplate(context);
416 if (name != null) {
417 template.setName(name);
418 }
419 template.setAutoCreated(autoCreated);
420 template.setMandatory(mandatory);
421 template.setMultiple(multiple);
422 template.setProtected(isProtected);
423 template.setFullTextSearchable(isSearchable);
424 template.setAvailableQueryOperators(queryOps.toArray(new String[queryOps.size()]));
425 template.setQueryOrderable(isOrderable);
426 template.setProtected(isProtected);
427 template.setOnParentVersion(onParentVersion);
428 template.setDefaultValues(defaultValues.toArray(new Value[defaultValues.size()]));
429 template.setRequiredType(requiredType);
430 template.setValueConstraints(constraints.toArray(new String[constraints.size()]));
431 return template;
432 }
433
434 protected NodeDefinitionTemplate childNodeDefinitionFrom( Subgraph nodeTypeGraph,
435 Location childNodeLocation ) throws ConstraintViolationException {
436 SubgraphNode childNodeDefinitionNode = nodeTypeGraph.getNode(childNodeLocation);
437
438 String childNodeName = readString(childNodeDefinitionNode, JcrLexicon.NAME, null);
439 String defaultPrimaryTypeName = readString(childNodeDefinitionNode, JcrLexicon.DEFAULT_PRIMARY_TYPE, null);
440 String onParentVersionName = readString(childNodeDefinitionNode,
441 JcrLexicon.ON_PARENT_VERSION,
442 OnParentVersionAction.nameFromValue(OnParentVersionAction.COPY));
443 int onParentVersion = OnParentVersionAction.valueFromName(onParentVersionName);
444
445 boolean mandatory = readBoolean(childNodeDefinitionNode, JcrLexicon.MANDATORY, false);
446 boolean allowsSns = readBoolean(childNodeDefinitionNode, JcrLexicon.SAME_NAME_SIBLINGS, false);
447 boolean autoCreated = readBoolean(childNodeDefinitionNode, JcrLexicon.AUTO_CREATED, false);
448 boolean isProtected = readBoolean(childNodeDefinitionNode, JcrLexicon.PROTECTED, false);
449 List<String> requiredTypes = readStrings(childNodeDefinitionNode, JcrLexicon.REQUIRED_PRIMARY_TYPES);
450
451 NodeDefinitionTemplate template = new JcrNodeDefinitionTemplate(context);
452 if (childNodeName != null) {
453 template.setName(childNodeName);
454 }
455 template.setAutoCreated(autoCreated);
456 template.setMandatory(mandatory);
457 template.setSameNameSiblings(allowsSns);
458 template.setProtected(isProtected);
459 template.setOnParentVersion(onParentVersion);
460 template.setDefaultPrimaryTypeName(defaultPrimaryTypeName);
461 template.setRequiredPrimaryTypeNames(requiredTypes.toArray(new String[requiredTypes.size()]));
462 return template;
463 }
464
465 protected Name nameFrom( SubgraphNode node ) {
466 return node.getLocation().getPath().getLastSegment().getName();
467 }
468
469 protected Name name( String name ) {
470 return nameFactory.create(name);
471 }
472
473 protected String string( Object value ) {
474 return stringFactory.create(value);
475 }
476
477 protected boolean readBoolean( SubgraphNode node,
478 String propertyName,
479 boolean defaultValue ) {
480 return readBoolean(node, nameFactory.create(propertyName), defaultValue);
481 }
482
483 protected boolean readBoolean( SubgraphNode node,
484 Name propertyName,
485 boolean defaultValue ) {
486 Property property = node.getProperty(propertyName);
487 return property != null ? booleanFactory.create(property.getFirstValue()) : defaultValue;
488 }
489
490 protected String readString( SubgraphNode node,
491 String propertyName,
492 String defaultValue ) {
493 return readString(node, nameFactory.create(propertyName), defaultValue);
494 }
495
496 protected String readString( SubgraphNode node,
497 Name propertyName,
498 String defaultValue ) {
499 Property property = node.getProperty(propertyName);
500 return property != null ? stringFactory.create(property.getFirstValue()) : defaultValue;
501 }
502
503 protected List<String> readStrings( SubgraphNode node,
504 String propertyName ) {
505 return readStrings(node, nameFactory.create(propertyName));
506 }
507
508 protected List<String> readStrings( SubgraphNode node,
509 Name propertyName ) {
510 List<String> results = new ArrayList<String>();
511 Property property = node.getProperty(propertyName);
512 if (property != null) {
513 for (Object value : property) {
514 String str = stringFactory.create(value);
515 if (str != null && str.length() != 0) results.add(str);
516 }
517 }
518 return results;
519 }
520
521 protected List<Value> readValues( SubgraphNode node,
522 Name propertyName,
523 int requiredType ) {
524 List<String> results = readStrings(node, propertyName);
525 List<Value> values = new ArrayList<Value>(results.size());
526 for (String result : results) {
527 values.add(new JcrValue(valueFactories, null, requiredType, result));
528 }
529 return values;
530 }
531
532 protected Name readName( SubgraphNode node,
533 String propertyName,
534 Name defaultValue ) {
535 return readName(node, nameFactory.create(propertyName), defaultValue);
536 }
537
538 protected Name readName( SubgraphNode node,
539 Name propertyName,
540 Name defaultValue ) {
541 Property property = node.getProperty(propertyName);
542 if (property != null && !property.isEmpty()) {
543 String firstValue = stringFactory.create(property.getFirstValue());
544 if (firstValue != null && firstValue.trim().length() != 0) {
545 return valueFactories.getNameFactory().create(firstValue);
546 }
547 }
548 return defaultValue;
549 }
550
551 protected List<Name> readNames( SubgraphNode node,
552 String propertyName,
553 Name defaultIfNone ) {
554 return readNames(node, nameFactory.create(propertyName), defaultIfNone);
555 }
556
557 protected List<Name> readNames( SubgraphNode node,
558 Name propertyName,
559 Name defaultIfNone ) {
560 List<Name> results = new ArrayList<Name>();
561 Property property = node.getProperty(propertyName);
562 if (property != null) {
563 for (Object value : property) {
564 Name name = nameFactory.create(value);
565 if (name != null) results.add(name);
566 }
567 }
568 if (results.isEmpty() && defaultIfNone != null) results.add(defaultIfNone);
569 return results;
570 }
571
572
573
574
575
576
577
578
579
580
581 protected void importFrom( Destination graphDestination,
582 Path path,
583 String content,
584 String resourceName ) throws Exception {
585 throw new UnsupportedOperationException();
586 }
587
588 }