001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.hivemind.impl;
016
017import java.util.HashSet;
018import java.util.Iterator;
019import java.util.List;
020import java.util.Locale;
021import java.util.Set;
022
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.apache.hivemind.ErrorHandler;
026import org.apache.hivemind.ModuleDescriptorProvider;
027import org.apache.hivemind.Registry;
028import org.apache.hivemind.internal.RegistryInfrastructure;
029import org.apache.hivemind.parse.ModuleDescriptor;
030
031/**
032 * Class used to build a {@link org.apache.hivemind.Registry} from individual
033 * {@link org.apache.hivemind.parse.ModuleDescriptor}. The descriptors are provided by the
034 * {@link ModuleDescriptorProvider}parameter passed to {@link #constructRegistry(Locale)} method.
035 * <p>
036 * A note about threadsafety: The assumption is that a single thread will access the RegistryBuilder
037 * at one time (typically, a startup class within some form of server or application). Code here and
038 * in many of the related classes is divided into construction-time logic and runtime logic. Runtime
039 * logic is synchronized and threadsafe. Construction-time logic is not threadsafe. Once the
040 * registry is fully constructed, it is not allowed to invoke those methods (though, at this time,
041 * no checks occur).
042 * <p>
043 * Runtime methods, such as {@link org.apache.hivemind.impl.ModuleImpl#getService(String, Class)}
044 * are fully threadsafe.
045 * 
046 * @author Howard Lewis Ship
047 */
048public final class RegistryBuilder
049{
050    private static final Log LOG = LogFactory.getLog(RegistryBuilder.class);
051
052    static
053    {
054        if (!LOG.isErrorEnabled())
055        {
056            System.err
057                    .println("********************************************************************************");
058            System.err
059                    .println("* L O G G I N G   C O N F I G U R A T I O N   E R R O R                        *");
060            System.err
061                    .println("* ---------------------------------------------------------------------------- *");
062            System.err
063                    .println("* Logging is not enabled for org.apache.hivemind.impl.RegistryBuilder.         *");
064            System.err
065                    .println("* Errors during HiveMind module descriptor parsing and validation may not be   *");
066            System.err
067                    .println("* logged. This may result in difficult-to-trace runtime exceptions, if there   *");
068            System.err
069                    .println("* are errors in any of your module descriptors. You should enable error        *");
070            System.err
071                    .println("* logging for the org.apache.hivemind and hivemind loggers.                    *");
072            System.err
073                    .println("********************************************************************************");
074        }
075    }
076
077    /**
078     * Delegate used for handling errors.
079     */
080
081    private ErrorHandler _errorHandler;
082
083    /**
084     * RegistryAssembly used by the module descriptor parser(s).
085     */
086
087    private RegistryAssemblyImpl _registryAssembly;
088
089    /**
090     * A set of all {@link ModuleDescriptorProvider} objects used to construct the Registry.
091     * 
092     * @since 1.1
093     */
094
095    private Set _moduleDescriptorProviders;
096
097    /**
098     * Contains most of the logic for actually creating the registry.
099     * 
100     * @since 1.1
101     */
102
103    private RegistryInfrastructureConstructor _constructor;
104
105    public RegistryBuilder()
106    {
107        this(new DefaultErrorHandler());
108    }
109
110    public RegistryBuilder(ErrorHandler handler)
111    {
112        _errorHandler = handler;
113
114        _registryAssembly = new RegistryAssemblyImpl();
115
116        _moduleDescriptorProviders = new HashSet();
117
118        _constructor = new RegistryInfrastructureConstructor(handler, LOG, _registryAssembly);
119    }
120
121    /**
122     * Adds a {@link ModuleDescriptorProvider} as a source for
123     * {@link ModuleDescriptor module descriptors} to this RegistryBuilder. Adding the same provider
124     * instance multiple times has no effect.
125     * 
126     * @since 1.1
127     */
128    public void addModuleDescriptorProvider(ModuleDescriptorProvider provider)
129    {
130        _moduleDescriptorProviders.add(provider);
131    }
132
133    /**
134     * This first loads all modules provided by the ModuleDescriptorProvider, then resolves all the
135     * contributions, then constructs and returns the Registry.
136     */
137    public Registry constructRegistry(Locale locale)
138    {
139        for (Iterator i = _moduleDescriptorProviders.iterator(); i.hasNext();)
140        {
141            ModuleDescriptorProvider provider = (ModuleDescriptorProvider) i.next();
142
143            processModuleDescriptorProvider(provider);
144        }
145
146        // Process any deferred operations. Post processing is added by
147        // both the parser and the registry constructor.
148
149        _registryAssembly.performPostProcessing();
150
151        RegistryInfrastructure infrastructure = _constructor
152                .constructRegistryInfrastructure(locale);
153
154        infrastructure.startup();
155
156        return new RegistryImpl(infrastructure);
157    }
158
159    private void processModuleDescriptorProvider(ModuleDescriptorProvider provider)
160    {
161        List descriptors = provider.getModuleDescriptors(_errorHandler);
162
163        Iterator i = descriptors.iterator();
164        while (i.hasNext())
165        {
166            ModuleDescriptor md = (ModuleDescriptor) i.next();
167
168            _constructor.addModuleDescriptor(md);
169        }
170    }
171
172    /**
173     * Adds a default module descriptor provider to this <code>RegistryBuilder</code>. A default
174     * module descriptor provider is merely a {@link XmlModuleDescriptorProvider} constructed with a
175     * {@link DefaultClassResolver}.
176     * 
177     * @since 1.1
178     */
179    public void addDefaultModuleDescriptorProvider()
180    {
181        addModuleDescriptorProvider(new XmlModuleDescriptorProvider(new DefaultClassResolver()));
182    }
183
184    /**
185     * Constructs a default registry based on just the modules visible to the thread context class
186     * loader (this is sufficient is the majority of cases), and using the default locale. If you
187     * have different error handling needs, or wish to pick up HiveMind module deployment
188     * descriptors for non-standard locations, you must create a RegistryBuilder instance yourself.
189     * 
190     * @see #addDefaultModuleDescriptorProvider()
191     */
192    public static Registry constructDefaultRegistry()
193    {
194        RegistryBuilder builder = new RegistryBuilder();
195        builder.addDefaultModuleDescriptorProvider();
196        return builder.constructRegistry(Locale.getDefault());
197    }
198
199}