View Javadoc

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(&quot;Source1&quot;).setClass(InMemoryRepositorySource.class).setDescription(&quot;description&quot;);
64   * configuration.mimeTypeDetector(&quot;detector&quot;).setClass(ExtensionBasedMimeTypeDetector.class).setDescription(&quot;default detector&quot;);
65   * configuration.sequencer(&quot;MicrosoftDocs&quot;)
66   *              .setClass(&quot;org.modeshape.sequencer.msoffice.MSOfficeMetadataSequencer&quot;)
67   *              .setDescription(&quot;Our primary sequencer for all .doc files&quot;)
68   *              .sequencingFrom(&quot;/public//(*.(doc|xml|ppt)[*]/jcr:content[@jcr:data]&quot;)
69   *              .andOutputtingTo(&quot;/documents/$1&quot;);
70   * configuration.repository(&quot;MyRepository&quot;).setSource(&quot;Source1&quot;);
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 }