001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors.
008     *
009     * Unless otherwise indicated, all code in JBoss DNA is licensed
010     * to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     * 
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.repository;
025    
026    import java.util.Collections;
027    import java.util.HashMap;
028    import java.util.Map;
029    import org.jboss.dna.common.util.CheckArg;
030    import org.jboss.dna.graph.ExecutionContext;
031    import org.jboss.dna.graph.Graph;
032    import org.jboss.dna.graph.Node;
033    import org.jboss.dna.graph.connector.RepositorySource;
034    import org.jboss.dna.graph.mimetype.MimeTypeDetector;
035    import org.jboss.dna.graph.property.Name;
036    import org.jboss.dna.graph.property.Path;
037    import org.jboss.dna.repository.Configurator.ChooseClass;
038    import org.jboss.dna.repository.Configurator.ConfigRepositoryDetails;
039    import org.jboss.dna.repository.Configurator.ConfigurationRepository;
040    import org.jboss.dna.repository.Configurator.MimeTypeDetectorDetails;
041    import org.jboss.dna.repository.Configurator.RepositoryDetails;
042    import org.jboss.dna.repository.Configurator.SequencerDetails;
043    import org.jboss.dna.repository.sequencer.Sequencer;
044    
045    /**
046     * 
047     */
048    public class DnaConfiguration
049        implements Configurator.Initializer<DnaConfiguration>, Configurator.SequencerConfigurator<DnaConfiguration>,
050        Configurator.RepositoryConfigurator<DnaConfiguration>, Configurator.MimeDetectorConfigurator<DnaConfiguration>,
051        Configurator.Builder<DnaEngine> {
052    
053        protected static final Map<String, Name> NAMES_TO_MAP;
054        static {
055            Map<String, Name> names = new HashMap<String, Name>();
056            names.put(DnaLexicon.READABLE_NAME.getLocalName(), DnaLexicon.READABLE_NAME);
057            names.put(DnaLexicon.DESCRIPTION.getLocalName(), DnaLexicon.DESCRIPTION);
058            names.put(DnaLexicon.DEFAULT_CACHE_POLICY.getLocalName(), DnaLexicon.DEFAULT_CACHE_POLICY);
059            names.put(DnaLexicon.RETRY_LIMIT.getLocalName(), DnaLexicon.RETRY_LIMIT);
060            names.put(DnaLexicon.PATH_EXPRESSIONS.getLocalName(), DnaLexicon.PATH_EXPRESSIONS);
061            names.put(DnaLexicon.CLASSNAME.getLocalName(), DnaLexicon.CLASSNAME);
062            names.put(DnaLexicon.CLASSPATH.getLocalName(), DnaLexicon.CLASSPATH);
063            NAMES_TO_MAP = Collections.unmodifiableMap(names);
064        }
065    
066        private final Builder<DnaConfiguration> builder;
067    
068        /**
069         * Create a new configuration for DNA.
070         */
071        public DnaConfiguration() {
072            this(new ExecutionContext());
073        }
074    
075        /**
076         * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
077         * 
078         * @param context the new context, or null if a default-constructed execution context should be used
079         * @throws IllegalArgumentException if the supplied context reference is null
080         */
081        public DnaConfiguration( ExecutionContext context ) {
082            this.builder = new Builder<DnaConfiguration>(context, this);
083        }
084    
085        /**
086         * Get the execution context used by this configurator.
087         * 
088         * @return the execution context; never null
089         */
090        public final ExecutionContext getExecutionContext() {
091            return builder.getExecutionContext();
092        }
093    
094        /**
095         * {@inheritDoc}
096         * 
097         * @see org.jboss.dna.repository.Configurator.Initializer#withConfigurationRepository()
098         */
099        public ChooseClass<RepositorySource, ConfigRepositoryDetails<DnaConfiguration>> withConfigurationRepository() {
100            return builder.withConfigurationRepository();
101        }
102    
103        /**
104         * {@inheritDoc}
105         * 
106         * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(java.lang.String)
107         */
108        public ChooseClass<RepositorySource, RepositoryDetails<DnaConfiguration>> addRepository( String id ) {
109            return builder.addRepository(id);
110        }
111    
112        /**
113         * {@inheritDoc}
114         * 
115         * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(org.jboss.dna.graph.connector.RepositorySource)
116         */
117        public DnaConfiguration addRepository( RepositorySource source ) {
118            return builder.addRepository(source);
119        }
120    
121        /**
122         * {@inheritDoc}
123         * 
124         * @see org.jboss.dna.repository.Configurator.SequencerConfigurator#addSequencer(java.lang.String)
125         */
126        public ChooseClass<Sequencer, SequencerDetails<DnaConfiguration>> addSequencer( String id ) {
127            return builder.addSequencer(id);
128        }
129    
130        /**
131         * {@inheritDoc}
132         * 
133         * @see org.jboss.dna.repository.Configurator.MimeDetectorConfigurator#addMimeTypeDetector(java.lang.String)
134         */
135        public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails<DnaConfiguration>> addMimeTypeDetector( String id ) {
136            return builder.addMimeTypeDetector(id);
137        }
138    
139        /**
140         * Save any changes that have been made so far to the configuration. This method does nothing if no changes have been made.
141         * 
142         * @return this configuration object for method chaining purposes; never null
143         */
144        public DnaConfiguration save() {
145            return builder.save();
146        }
147    
148        /**
149         * {@inheritDoc}
150         * 
151         * @see org.jboss.dna.repository.Configurator.Builder#build()
152         */
153        public DnaEngine build() throws DnaConfigurationException {
154            save();
155            return new DnaEngine(builder.getExecutionContext(), builder.configurationSource);
156        }
157    
158        protected Graph graph() {
159            return builder.graph();
160        }
161    
162        protected ConfigurationRepository configurationRepository() {
163            return builder.configurationSource;
164        }
165    
166        public static class Builder<ReturnType> extends Configurator<ReturnType>
167            implements Configurator.Initializer<ReturnType>, Configurator.SequencerConfigurator<ReturnType>,
168            Configurator.RepositoryConfigurator<ReturnType>, Configurator.MimeDetectorConfigurator<ReturnType> {
169    
170            private Path sourcesPath;
171            private Path sequencersPath;
172            private Path detectorsPath;
173    
174            /**
175             * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
176             * 
177             * @param context the new context, or null if a default-constructed execution context should be used
178             * @param builder the builder object returned from all the methods
179             * @throws IllegalArgumentException if the supplied context reference is null
180             */
181            public Builder( ExecutionContext context,
182                            ReturnType builder ) {
183                super(context, builder);
184            }
185    
186            public DnaEngine buildDnaEngine() {
187                return new DnaEngine(context, configurationSource);
188            }
189    
190            public ConfigurationRepository getConfigurationRepository() {
191                return configurationSource;
192            }
193    
194            protected Path sourcesPath() {
195                // Make sure the "dna:sources" node is there
196                if (sourcesPath == null) {
197                    Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.SOURCES);
198                    Node node = graph().createIfMissing(path).andReturn();
199                    this.sourcesPath = node.getLocation().getPath();
200                }
201                return this.sourcesPath;
202            }
203    
204            protected Path sequencersPath() {
205                // Make sure the "dna:sequencers" node is there
206                if (sequencersPath == null) {
207                    Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.SEQUENCERS);
208                    Node node = graph().createIfMissing(path).andReturn();
209                    this.sequencersPath = node.getLocation().getPath();
210                }
211                return this.sequencersPath;
212            }
213    
214            protected Path detectorsPath() {
215                // Make sure the "dna:mimeTypeDetectors" node is there
216                if (detectorsPath == null) {
217                    Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.MIME_TYPE_DETECTORS);
218                    Node node = graph().createIfMissing(path).andReturn();
219                    this.detectorsPath = node.getLocation().getPath();
220                }
221                return this.detectorsPath;
222            }
223    
224            /**
225             * {@inheritDoc}
226             * 
227             * @see org.jboss.dna.repository.Configurator.Initializer#withConfigurationRepository()
228             */
229            public ChooseClass<RepositorySource, ConfigRepositoryDetails<ReturnType>> withConfigurationRepository() {
230                return new ConfigurationRepositoryClassChooser<ReturnType>(builder);
231            }
232    
233            /**
234             * {@inheritDoc}
235             * 
236             * @see org.jboss.dna.repository.Configurator.SequencerConfigurator#addSequencer(java.lang.String)
237             */
238            public ChooseClass<Sequencer, SequencerDetails<ReturnType>> addSequencer( String id ) {
239                CheckArg.isNotEmpty(id, "id");
240                // Now create the "dna:sequencer" node with the supplied id ...
241                Path path = createOrReplaceNode(sequencersPath(), id);
242                SequencerDetails<ReturnType> details = new GraphSequencerDetails<ReturnType>(path, builder);
243                return new ClassChooser<Sequencer, SequencerDetails<ReturnType>>(path, details);
244            }
245    
246            /**
247             * {@inheritDoc}
248             * 
249             * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(java.lang.String)
250             */
251            public ChooseClass<RepositorySource, RepositoryDetails<ReturnType>> addRepository( String id ) {
252                CheckArg.isNotEmpty(id, "id");
253                // Now create the "dna:source" node with the supplied id ...
254                Path path = createOrReplaceNode(sourcesPath(), id);
255                RepositoryDetails<ReturnType> details = new GraphRepositoryDetails<ReturnType>(path, builder);
256                return new ClassChooser<RepositorySource, RepositoryDetails<ReturnType>>(path, details);
257            }
258    
259            /**
260             * {@inheritDoc}
261             * 
262             * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(org.jboss.dna.graph.connector.RepositorySource)
263             */
264            public ReturnType addRepository( RepositorySource source ) {
265                CheckArg.isNotNull(source, "source");
266                CheckArg.isNotEmpty(source.getName(), "source.getName()");
267                String name = source.getName();
268                RepositoryDetails<ReturnType> details = addRepository(source.getName()).usingClass(source.getClass().getName())
269                                                                                       .loadedFromClasspath();
270                // Record all of the bean properties ...
271                Path sourcePath = pathFactory().create(sourcesPath(), name);
272                recordBeanPropertiesInGraph(sourcePath, source);
273                return details.and();
274            }
275    
276            /**
277             * {@inheritDoc}
278             * 
279             * @see org.jboss.dna.repository.Configurator.MimeDetectorConfigurator#addMimeTypeDetector(java.lang.String)
280             */
281            public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails<ReturnType>> addMimeTypeDetector( String id ) {
282                CheckArg.isNotEmpty(id, "id");
283                // Now create the "dna:sequencer" node with the supplied id ...
284                Path detectorPath = createOrReplaceNode(detectorsPath(), id);
285                MimeTypeDetectorDetails<ReturnType> details = new GraphMimeTypeDetectorDetails<ReturnType>(detectorPath, builder);
286                return new ClassChooser<MimeTypeDetector, MimeTypeDetectorDetails<ReturnType>>(detectorPath, details);
287            }
288    
289            /**
290             * {@inheritDoc}
291             * 
292             * @see org.jboss.dna.repository.Configurator#nameFor(java.lang.String)
293             */
294            @Override
295            protected Name nameFor( String name ) {
296                Name result = NAMES_TO_MAP.get(name);
297                if (result == null) result = context.getValueFactories().getNameFactory().create(name);
298                return result;
299            }
300        }
301    
302    }