1 /*
2 * ModeShape (http://www.modeshape.org)
3 * See the COPYRIGHT.txt file distributed with this work for information
4 * regarding copyright ownership. Some portions may be licensed
5 * to Red Hat, Inc. under one or more contributor license agreements.
6 * See the AUTHORS.txt file in the distribution for a full listing of
7 * individual contributors.
8 *
9 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10 * is licensed to you under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * ModeShape is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this software; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
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.Collections;
31 import java.util.EnumMap;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Map;
35 import java.util.Set;
36 import net.jcip.annotations.NotThreadSafe;
37 import org.modeshape.cnd.CndImporter;
38 import org.modeshape.common.component.ClassLoaderFactory;
39 import org.modeshape.common.util.CheckArg;
40 import org.modeshape.graph.ExecutionContext;
41 import org.modeshape.graph.Graph;
42 import org.modeshape.graph.Location;
43 import org.modeshape.graph.Node;
44 import org.modeshape.graph.Subgraph;
45 import org.modeshape.graph.connector.RepositorySource;
46 import org.modeshape.graph.io.Destination;
47 import org.modeshape.graph.io.GraphBatchDestination;
48 import org.modeshape.graph.property.Name;
49 import org.modeshape.graph.property.Path;
50 import org.modeshape.graph.property.PathNotFoundException;
51 import org.modeshape.graph.property.Property;
52 import org.modeshape.graph.property.NamespaceRegistry.Namespace;
53 import org.modeshape.jcr.JcrRepository.Option;
54 import org.modeshape.repository.ModeShapeConfiguration;
55 import org.modeshape.repository.ModeShapeConfigurationException;
56 import org.xml.sax.SAXException;
57
58 /**
59 * A configuration builder for a {@link JcrEngine}. This class is an internal domain-specific language (DSL), and is designed to
60 * be used in a traditional way or in a method-chained manner:
61 *
62 * <pre>
63 * configuration.repositorySource("Source1").setClass(InMemoryRepositorySource.class).setDescription("description");
64 * configuration.mimeTypeDetector("detector").setClass(ExtensionBasedMimeTypeDetector.class).setDescription("default detector");
65 * configuration.sequencer("MicrosoftDocs")
66 * .setClass("org.modeshape.sequencer.msoffice.MSOfficeMetadataSequencer")
67 * .setDescription("Our primary sequencer for all .doc files")
68 * .sequencingFrom("/public//(*.(doc|xml|ppt)[*]/jcr:content[@jcr:data]")
69 * .andOutputtingTo("/documents/$1");
70 * configuration.repository("MyRepository").setSource("Source1");
71 * configuration.save();
72 * </pre>
73 */
74 @NotThreadSafe
75 public class JcrConfiguration extends ModeShapeConfiguration {
76
77 /**
78 * Interface used to define a JCR Repository that's accessible from the JcrEngine.
79 *
80 * @param <ReturnType>
81 */
82 public interface RepositoryDefinition<ReturnType>
83 extends Returnable<ReturnType>, Removable<ReturnType>, SetDescription<RepositoryDefinition<ReturnType>> {
84
85 /**
86 * Specify the name of the repository source that is to be used by this JCR repository.
87 *
88 * @param sourceName the name of the repository source that should be exposed by this JCR repository
89 * @return the interface used to set the value for the property; never null
90 * @throws IllegalArgumentException if the source name parameter is null
91 */
92 RepositoryDefinition<ReturnType> setSource( String sourceName );
93
94 /**
95 * Get the name of the repository source that is to be used by this JCR repository.
96 *
97 * @return the source name, or null if it has not yet been set
98 */
99 String getSource();
100
101 /**
102 * Specify the repository option that is to be set.
103 *
104 * @param option the option to be set
105 * @param value the new value for the option
106 * @return the interface used to set the value for the property; never null
107 * @throws IllegalArgumentException if either parameter is null
108 */
109 RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
110 String value );
111
112 /**
113 * Specify the repository option that is to be set.
114 *
115 * @param option the option to be set
116 * @param value the new value for the option
117 * @return the interface used to set the value for the property; never null
118 * @throws IllegalArgumentException if either parameter is null
119 */
120 RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
121 boolean value );
122
123 /**
124 * Specify the repository option that is to be set.
125 *
126 * @param option the option to be set
127 * @param value the new value for the option
128 * @return the interface used to set the value for the property; never null
129 * @throws IllegalArgumentException if either parameter is null
130 */
131 RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
132 int value );
133
134 /**
135 * Specify the repository option that is to be set.
136 *
137 * @param option the option to be set
138 * @param value the new value for the option
139 * @return the interface used to set the value for the property; never null
140 * @throws IllegalArgumentException if either parameter is null
141 */
142 RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
143 long value );
144
145 /**
146 * Specify the repository option that is to be set.
147 *
148 * @param option the option to be set
149 * @param value the new value for the option
150 * @return the interface used to set the value for the property; never null
151 * @throws IllegalArgumentException if either parameter is null
152 */
153 RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
154 float value );
155
156 /**
157 * Specify the repository option that is to be set.
158 *
159 * @param option the option to be set
160 * @param value the new value for the option
161 * @return the interface used to set the value for the property; never null
162 * @throws IllegalArgumentException if either parameter is null
163 */
164 RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
165 double value );
166
167 /**
168 * Get the value for the repository option.
169 *
170 * @param option the option
171 * @return the current option value, which may be null if the option has not been set (and its default would be used)
172 * @throws IllegalArgumentException if the option parameter is null
173 */
174 String getOption( JcrRepository.Option option );
175
176 /**
177 * Specify that the CND file located at the supplied path should be loaded into the repository.
178 * <p>
179 * This method may be called multiple times, once per CND file.
180 * </p>
181 *
182 * @param pathToCndFile the path to the CND file
183 * @return this object for chained method invocation
184 * @throws IllegalArgumentException if the string is null or empty
185 * @throws ModeShapeConfigurationException if there is an error reading the CND file
186 */
187 RepositoryDefinition<ReturnType> addNodeTypes( String pathToCndFile );
188
189 /**
190 * Specify that the CND file is to be loaded into the repository.
191 *
192 * @param cndFile the CND file
193 * @return this object for chained method invocation
194 * @throws IllegalArgumentException if the file is null
195 * @throws ModeShapeConfigurationException if there is an error reading the file
196 */
197 RepositoryDefinition<ReturnType> addNodeTypes( File cndFile );
198
199 /**
200 * Specify that the CND file is to be loaded into the repository.
201 * <p>
202 * This method may be called multiple times, once per CND file.
203 * </p>
204 *
205 * @param urlOfCndFile the URL of the CND file
206 * @return this object for chained method invocation
207 * @throws IllegalArgumentException if the URL is null
208 * @throws ModeShapeConfigurationException if there is an error reading the content at the URL
209 */
210 RepositoryDefinition<ReturnType> addNodeTypes( URL urlOfCndFile );
211
212 /**
213 * Specify that the CND file is to be loaded into the repository.
214 * <p>
215 * This method may be called multiple times, once per CND file.
216 * </p>
217 *
218 * @param cndContent the stream containing the CND content
219 * @return this object for chained method invocation
220 * @throws IllegalArgumentException if the URL is null
221 * @throws ModeShapeConfigurationException if there is an error reading the stream at the URL
222 */
223 RepositoryDefinition<ReturnType> addNodeTypes( InputStream cndContent );
224
225 /**
226 * Specify the namespace binding that should be made available in this repository.
227 *
228 * @param prefix the namespace prefix; may not be null or empty, and must be a valid prefix
229 * @param uri the uri for the namespace; may not be null or empty
230 * @return the interface used to set the value for the property; never null
231 */
232 RepositoryDefinition<ReturnType> registerNamespace( String prefix,
233 String uri );
234 }
235
236 private final Map<String, RepositoryDefinition<? extends JcrConfiguration>> repositoryDefinitions = new HashMap<String, RepositoryDefinition<? extends JcrConfiguration>>();
237
238 /**
239 * Create a new configuration, using a default-constructed {@link ExecutionContext}.
240 */
241 public JcrConfiguration() {
242 super();
243 }
244
245 /**
246 * Create a new configuration using the supplied {@link ExecutionContext}.
247 *
248 * @param context the execution context
249 * @throws IllegalArgumentException if the path is null or empty
250 */
251 public JcrConfiguration( ExecutionContext context ) {
252 super(context);
253 }
254
255 /**
256 * {@inheritDoc}
257 *
258 * @throws IOException
259 * @throws SAXException
260 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.lang.String)
261 */
262 @Override
263 public JcrConfiguration loadFrom( String pathToFile ) throws IOException, SAXException {
264 super.loadFrom(pathToFile);
265 return this;
266 }
267
268 /**
269 * {@inheritDoc}
270 *
271 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.lang.String, java.lang.String)
272 */
273 @Override
274 public JcrConfiguration loadFrom( String pathToConfigurationFile,
275 String path ) throws IOException, SAXException {
276 super.loadFrom(pathToConfigurationFile, path);
277 return this;
278 }
279
280 /**
281 * {@inheritDoc}
282 *
283 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.io.File)
284 */
285 @Override
286 public JcrConfiguration loadFrom( File configurationFile ) throws IOException, SAXException {
287 super.loadFrom(configurationFile);
288 return this;
289 }
290
291 /**
292 * {@inheritDoc}
293 *
294 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.io.File, java.lang.String)
295 */
296 @Override
297 public JcrConfiguration loadFrom( File configurationFile,
298 String path ) throws IOException, SAXException {
299 super.loadFrom(configurationFile, path);
300 return this;
301 }
302
303 /**
304 * {@inheritDoc}
305 *
306 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.net.URL)
307 */
308 @Override
309 public JcrConfiguration loadFrom( URL urlToConfigurationFile ) throws IOException, SAXException {
310 super.loadFrom(urlToConfigurationFile);
311 return this;
312 }
313
314 /**
315 * {@inheritDoc}
316 *
317 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.net.URL, java.lang.String)
318 */
319 @Override
320 public JcrConfiguration loadFrom( URL urlToConfigurationFile,
321 String path ) throws IOException, SAXException {
322 super.loadFrom(urlToConfigurationFile, path);
323 return this;
324 }
325
326 /**
327 * {@inheritDoc}
328 *
329 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.io.InputStream)
330 */
331 @Override
332 public JcrConfiguration loadFrom( InputStream configurationFileInputStream ) throws IOException, SAXException {
333 super.loadFrom(configurationFileInputStream);
334 return this;
335 }
336
337 /**
338 * {@inheritDoc}
339 *
340 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(java.io.InputStream, java.lang.String)
341 */
342 @Override
343 public JcrConfiguration loadFrom( InputStream configurationFileInputStream,
344 String path ) throws IOException, SAXException {
345 super.loadFrom(configurationFileInputStream, path);
346 return this;
347 }
348
349 /**
350 * {@inheritDoc}
351 *
352 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(org.modeshape.graph.connector.RepositorySource)
353 */
354 @Override
355 public JcrConfiguration loadFrom( RepositorySource source ) {
356 super.loadFrom(source);
357 return this;
358 }
359
360 /**
361 * {@inheritDoc}
362 *
363 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(org.modeshape.graph.connector.RepositorySource,
364 * java.lang.String)
365 */
366 @Override
367 public JcrConfiguration loadFrom( RepositorySource source,
368 String workspaceName ) {
369 super.loadFrom(source, workspaceName);
370 return this;
371 }
372
373 /**
374 * {@inheritDoc}
375 *
376 * @see org.modeshape.repository.ModeShapeConfiguration#loadFrom(org.modeshape.graph.connector.RepositorySource,
377 * java.lang.String, java.lang.String)
378 */
379 @Override
380 public JcrConfiguration loadFrom( RepositorySource source,
381 String workspaceName,
382 String pathInWorkspace ) {
383 super.loadFrom(source, workspaceName, pathInWorkspace);
384 return this;
385 }
386
387 /**
388 * {@inheritDoc}
389 *
390 * @see org.modeshape.repository.ModeShapeConfiguration#and()
391 */
392 @Override
393 public JcrConfiguration and() {
394 return this;
395 }
396
397 /**
398 * {@inheritDoc}
399 *
400 * @see org.modeshape.repository.ModeShapeConfiguration#withClassLoaderFactory(org.modeshape.common.component.ClassLoaderFactory)
401 */
402 @Override
403 public JcrConfiguration withClassLoaderFactory( ClassLoaderFactory classLoaderFactory ) {
404 super.withClassLoaderFactory(classLoaderFactory);
405 return this;
406 }
407
408 /**
409 * {@inheritDoc}
410 *
411 * @see org.modeshape.repository.ModeShapeConfiguration#mimeTypeDetector(java.lang.String)
412 */
413 @Override
414 public MimeTypeDetectorDefinition<JcrConfiguration> mimeTypeDetector( String name ) {
415 return mimeTypeDetectorDefinition(this, name);
416 }
417
418 /**
419 * {@inheritDoc}
420 *
421 * @see org.modeshape.repository.ModeShapeConfiguration#repositorySource(java.lang.String)
422 */
423 @Override
424 public RepositorySourceDefinition<JcrConfiguration> repositorySource( String name ) {
425 return repositorySourceDefinition(this, name);
426 }
427
428 /**
429 * {@inheritDoc}
430 *
431 * @see org.modeshape.repository.ModeShapeConfiguration#sequencer(java.lang.String)
432 */
433 @Override
434 public SequencerDefinition<JcrConfiguration> sequencer( String name ) {
435 return sequencerDefinition(this, name);
436 }
437
438 /**
439 * Obtain or create a definition for the {@link javax.jcr.Repository JCR Repository} with the supplied name or identifier. A
440 * new definition will be created if there currently is no sequencer defined with the supplied name.
441 *
442 * @param name the name or identifier of the sequencer
443 * @return the details of the sequencer definition; never null
444 */
445 public RepositoryDefinition<JcrConfiguration> repository( String name ) {
446 return repositoryDefinition(this, name);
447 }
448
449 /**
450 * Get the list of sequencer definitions.
451 *
452 * @return the unmodifiable set of definitions; never null but possibly empty if there are no definitions
453 */
454 public Set<RepositoryDefinition<JcrConfiguration>> repositories() {
455 // Get the children under the 'dna:mimeTypeDetectors' node ...
456 Set<String> names = getNamesOfComponentsUnder(ModeShapeLexicon.REPOSITORIES);
457 names.addAll(this.repositoryDefinitions.keySet());
458 Set<RepositoryDefinition<JcrConfiguration>> results = new HashSet<RepositoryDefinition<JcrConfiguration>>();
459 for (String name : names) {
460 results.add(repository(name));
461 }
462 return Collections.unmodifiableSet(results);
463 }
464
465 /**
466 * {@inheritDoc}
467 *
468 * @see org.modeshape.repository.ModeShapeConfiguration#save()
469 */
470 @Override
471 public JcrConfiguration save() {
472 super.save();
473 this.repositoryDefinitions.clear();
474 return this;
475 }
476
477 /**
478 * {@inheritDoc}
479 *
480 * @see org.modeshape.repository.ModeShapeConfiguration#build()
481 */
482 @Override
483 public JcrEngine build() {
484 save();
485 return new JcrEngine(getExecutionContextForEngine(), getConfigurationDefinition());
486 }
487
488 /**
489 * Utility method to construct a definition object for the repository with the supplied name and return type.
490 *
491 * @param <ReturnType> the type of the return object
492 * @param returnObject the return object
493 * @param name the name of the repository
494 * @return the definition for the repository
495 */
496 @SuppressWarnings( "unchecked" )
497 protected <ReturnType extends JcrConfiguration> RepositoryDefinition<ReturnType> repositoryDefinition( ReturnType returnObject,
498 String name ) {
499 RepositoryDefinition<ReturnType> definition = (RepositoryDefinition<ReturnType>)repositoryDefinitions.get(name);
500 if (definition == null) {
501 definition = new RepositoryBuilder<ReturnType>(returnObject, changes(), path(), ModeShapeLexicon.REPOSITORIES,
502 name(name));
503 repositoryDefinitions.put(name, definition);
504 }
505 return definition;
506 }
507
508 protected class RepositoryBuilder<ReturnType> extends GraphReturnable<ReturnType, RepositoryDefinition<ReturnType>>
509 implements RepositoryDefinition<ReturnType> {
510 private final EnumMap<JcrRepository.Option, String> optionValues = new EnumMap<Option, String>(Option.class);
511
512 protected RepositoryBuilder( ReturnType returnObject,
513 Graph.Batch batch,
514 Path path,
515 Name... names ) {
516 super(returnObject, batch, path, names);
517 // Load the current options ...
518 try {
519 Path optionsPath = context.getValueFactories().getPathFactory().create(path, ModeShapeLexicon.OPTIONS);
520 Subgraph options = batch.getGraph().getSubgraphOfDepth(2).at(optionsPath);
521 for (Location optionChild : options.getRoot().getChildren()) {
522 Node option = options.getNode(optionChild);
523 Property property = option.getProperty(ModeShapeLexicon.VALUE);
524 if (property != null && property.isEmpty()) {
525 try {
526 Option key = Option.findOption(optionChild.getPath()
527 .getLastSegment()
528 .getString(context.getNamespaceRegistry()));
529 String value = context.getValueFactories().getStringFactory().create(property.getFirstValue());
530 optionValues.put(key, value);
531 } catch (IllegalArgumentException e) {
532 // the key is not valid, so skip it ...
533 }
534 }
535 }
536 } catch (PathNotFoundException e) {
537 // No current options
538 }
539 }
540
541 @Override
542 protected RepositoryDefinition<ReturnType> thisType() {
543 return this;
544 }
545
546 public RepositoryDefinition<ReturnType> setSource( String sourceName ) {
547 setProperty(ModeShapeLexicon.SOURCE_NAME, sourceName);
548 return this;
549 }
550
551 public String getSource() {
552 Property property = getProperty(ModeShapeLexicon.SOURCE_NAME);
553 if (property != null && !property.isEmpty()) {
554 return context.getValueFactories().getStringFactory().create(property.getFirstValue());
555 }
556 return null;
557 }
558
559 public RepositoryDefinition<ReturnType> setOption( JcrRepository.Option option,
560 String value ) {
561 CheckArg.isNotNull(option, "option");
562 CheckArg.isNotNull(value, "value");
563 createIfMissing(ModeShapeLexicon.OPTIONS, option.name()).with(ModeShapeLexicon.VALUE, value.trim()).and();
564 optionValues.put(option, value);
565 return this;
566 }
567
568 public RepositoryDefinition<ReturnType> setOption( Option option,
569 boolean value ) {
570 return setOption(option, Boolean.toString(value));
571 }
572
573 public RepositoryDefinition<ReturnType> setOption( Option option,
574 int value ) {
575 return setOption(option, Integer.toString(value));
576 }
577
578 public RepositoryDefinition<ReturnType> setOption( Option option,
579 long value ) {
580 return setOption(option, Long.toString(value));
581 }
582
583 public RepositoryDefinition<ReturnType> setOption( Option option,
584 float value ) {
585 return setOption(option, Float.toString(value));
586 }
587
588 public RepositoryDefinition<ReturnType> setOption( Option option,
589 double value ) {
590 return setOption(option, Double.toString(value));
591 }
592
593 public String getOption( Option option ) {
594 CheckArg.isNotNull(option, "option");
595 return optionValues.get(option);
596 }
597
598 public RepositoryDefinition<ReturnType> registerNamespace( String prefix,
599 String uri ) {
600 CheckArg.isNotEmpty(prefix, "prefix");
601 CheckArg.isNotEmpty(uri, "uri");
602 prefix = prefix.trim();
603 uri = uri.trim();
604 createIfMissing(ModeShapeLexicon.NAMESPACES, prefix).with(ModeShapeLexicon.URI, uri).and();
605 return this;
606 }
607
608 public RepositoryDefinition<ReturnType> addNodeTypes( String pathToCndFile ) {
609 CheckArg.isNotEmpty(pathToCndFile, "pathToCndFile");
610 return addNodeTypes(new File(pathToCndFile));
611 }
612
613 public RepositoryDefinition<ReturnType> addNodeTypes( File file ) {
614 CheckArg.isNotNull(file, "file");
615 if (file.exists() && file.canRead()) {
616 CndImporter importer = createCndImporter();
617 try {
618 Set<Namespace> namespacesBefore = batch.getGraph().getContext().getNamespaceRegistry().getNamespaces();
619 importer.importFrom(file, getProblems());
620
621 // Record any new namespaces added by this import ...
622 registerNewNamespaces(namespacesBefore);
623 } catch (IOException e) {
624 throw new ModeShapeConfigurationException(e);
625 }
626 return this;
627 }
628 throw new ModeShapeConfigurationException(JcrI18n.fileDoesNotExist.text(file.getPath()));
629 }
630
631 public RepositoryDefinition<ReturnType> addNodeTypes( URL url ) {
632 CheckArg.isNotNull(url, "url");
633 // Obtain the stream ...
634 InputStream stream = null;
635 boolean foundError = false;
636 try {
637 Set<Namespace> namespacesBefore = batch.getGraph().getContext().getNamespaceRegistry().getNamespaces();
638 stream = url.openStream();
639 CndImporter importer = createCndImporter();
640 importer.importFrom(stream, getProblems(), url.toString());
641
642 // Record any new namespaces added by this import ...
643 registerNewNamespaces(namespacesBefore);
644 } catch (IOException e) {
645 foundError = true;
646 throw new ModeShapeConfigurationException(e);
647 } finally {
648 if (stream != null) {
649 try {
650 stream.close();
651 } catch (IOException e) {
652 if (!foundError) {
653 throw new ModeShapeConfigurationException(e);
654 }
655 }
656 }
657 }
658 return this;
659 }
660
661 public RepositoryDefinition<ReturnType> addNodeTypes( InputStream cndContent ) {
662 CndImporter importer = createCndImporter();
663 try {
664 Set<Namespace> namespacesBefore = batch.getGraph().getContext().getNamespaceRegistry().getNamespaces();
665 importer.importFrom(cndContent, getProblems(), "stream");
666
667 // Record any new namespaces added by this import ...
668 registerNewNamespaces(namespacesBefore);
669 } catch (IOException e) {
670 throw new ModeShapeConfigurationException(e);
671 }
672 return this;
673 }
674
675 protected void registerNewNamespaces( Set<Namespace> namespacesBefore ) {
676 Set<Namespace> namespacesAfter = batch.getGraph().getContext().getNamespaceRegistry().getNamespaces();
677 Set<Namespace> newNamespaces = new HashSet<Namespace>(namespacesAfter);
678 newNamespaces.removeAll(namespacesBefore);
679 for (Namespace namespace : newNamespaces) {
680 registerNamespace(namespace.getPrefix(), namespace.getNamespaceUri());
681 }
682 }
683
684 protected CndImporter createCndImporter() {
685 // The node types will be loaded into 'dna:repositories/{repositoryName}/dna:nodeTypes/' ...
686 Path nodeTypesPath = subpath(JcrLexicon.NODE_TYPES);
687 createIfMissing(JcrLexicon.NODE_TYPES).and();
688
689 // Now set up the destination, but make it so that ...
690 Destination destination = new GraphBatchDestination(batch, true); // will NOT be executed
691
692 // And create the importer that will load the CND content into the repository ...
693 return new CndImporter(destination, nodeTypesPath);
694 }
695 }
696
697 }