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    
015    package org.apache.hivemind.impl;
016    
017    import java.io.IOException;
018    import java.net.URL;
019    import java.util.ArrayList;
020    import java.util.Enumeration;
021    import java.util.Iterator;
022    import java.util.List;
023    
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.apache.hivemind.ApplicationRuntimeException;
027    import org.apache.hivemind.ClassResolver;
028    import org.apache.hivemind.ErrorHandler;
029    import org.apache.hivemind.HiveMind;
030    import org.apache.hivemind.ModuleDescriptorProvider;
031    import org.apache.hivemind.Resource;
032    import org.apache.hivemind.parse.ModuleDescriptor;
033    import org.apache.hivemind.parse.SubModuleDescriptor;
034    import org.apache.hivemind.parse.XmlResourceProcessor;
035    import org.apache.hivemind.util.URLResource;
036    
037    /**
038     * Implementation of the {@link ModuleDescriptorProvider} interface which uses the
039     * {@link org.apache.hivemind.parse.DescriptorParser} to provide module descriptors defined in XML.
040     * The module descriptors are loaded from files or resources on the classpath.
041     * 
042     * @author Knut Wannheden
043     * @since 1.1
044     */
045    public class XmlModuleDescriptorProvider implements ModuleDescriptorProvider
046    {
047        private static final Log LOG = LogFactory.getLog(XmlModuleDescriptorProvider.class);
048    
049        /**
050         * The default path, within a JAR or the classpath, to the XML HiveMind module deployment
051         * descriptor: <code>META-INF/hivemodule.xml</code>. Use this constant with the
052         * {@link #XmlModuleDescriptorProvider(ClassResolver, String)} constructor.
053         */
054        public static final String HIVE_MODULE_XML = "META-INF/hivemodule.xml";
055    
056        /**
057         * Set of all specified resources processed by this ModuleDescriptorProvider. Descriptors of
058         * sub-modules are not included.
059         */
060        private List _resources = new ArrayList();
061    
062        /**
063         * List of parsed {@link ModuleDescriptor} instances. Also includes referenced sub-modules.
064         */
065        private List _moduleDescriptors = new ArrayList();
066    
067        private ClassResolver _resolver;
068    
069        private ErrorHandler _errorHandler;
070    
071        /**
072         * Parser instance used by all parsing of module descriptors.
073         */
074        private XmlResourceProcessor _processor;
075    
076        /**
077         * Convenience constructor. Equivalent to using
078         * {@link #XmlModuleDescriptorProvider(ClassResolver, String)}with {@link #HIVE_MODULE_XML} as
079         * the second argument.
080         */
081        public XmlModuleDescriptorProvider(ClassResolver resolver)
082        {
083            this(resolver, HIVE_MODULE_XML);
084        }
085    
086        /**
087         * Loads all XML module descriptors found on the classpath (using the given
088         * {@link org.apache.hivemind.ClassResolver}. Only module descriptors matching the specified
089         * path are loaded. Use the {@link XmlModuleDescriptorProvider#HIVE_MODULE_XML} constant to load
090         * all descriptors in the default location.
091         */
092        public XmlModuleDescriptorProvider(ClassResolver resolver, String resourcePath)
093        {
094            _resolver = resolver;
095            _resources.addAll(getDescriptorResources(resourcePath, _resolver));
096        }
097    
098        /**
099         * Constructs an XmlModuleDescriptorProvider only loading the ModuleDescriptor identified by the
100         * given {@link org.apache.hivemind.Resource}.
101         */
102        public XmlModuleDescriptorProvider(ClassResolver resolver, Resource resource)
103        {
104            _resolver = resolver;
105            _resources.add(resource);
106        }
107    
108        /**
109         * Constructs an XmlModuleDescriptorProvider loading all ModuleDescriptor identified by the
110         * given List of {@link org.apache.hivemind.Resource} objects.
111         */
112        public XmlModuleDescriptorProvider(ClassResolver resolver, List resources)
113        {
114            _resolver = resolver;
115            _resources.addAll(resources);
116        }
117    
118        private List getDescriptorResources(String resourcePath, ClassResolver resolver)
119        {
120            if (LOG.isDebugEnabled())
121                LOG.debug("Processing modules visible to " + resolver);
122    
123            List descriptors = new ArrayList();
124    
125            ClassLoader loader = resolver.getClassLoader();
126            Enumeration e = null;
127    
128            try
129            {
130                e = loader.getResources(resourcePath);
131            }
132            catch (IOException ex)
133            {
134                throw new ApplicationRuntimeException(ImplMessages.unableToFindModules(resolver, ex),
135                        ex);
136            }
137    
138            while (e.hasMoreElements())
139            {
140                URL descriptorURL = (URL) e.nextElement();
141    
142                descriptors.add(new URLResource(descriptorURL));
143            }
144    
145            return descriptors;
146        }
147    
148        public List getModuleDescriptors(ErrorHandler handler)
149        {
150            _errorHandler = handler;
151    
152            _processor = getResourceProcessor(_resolver, handler);
153    
154            for (Iterator i = _resources.iterator(); i.hasNext();)
155            {
156                Resource resource = (Resource) i.next();
157    
158                processResource(resource);
159            }
160    
161            _processor = null;
162    
163            _errorHandler = null;
164    
165            return _moduleDescriptors;
166        }
167    
168        private void processResource(Resource resource)
169        {
170            try
171            {
172                ModuleDescriptor md = _processor.processResource(resource);
173    
174                _moduleDescriptors.add(md);
175    
176                // After parsing a module, parse any additional modules identified
177                // within the module (using the <sub-module> element) recursively.
178                processSubModules(md);
179            }
180            catch (RuntimeException ex)
181            {
182                _errorHandler.error(LOG, ex.getMessage(), HiveMind.getLocation(ex), ex);
183            }
184        }
185    
186        private void processSubModules(ModuleDescriptor moduleDescriptor)
187        {
188            List subModules = moduleDescriptor.getSubModules();
189    
190            if (subModules == null)
191                return;
192    
193            for (Iterator i = subModules.iterator(); i.hasNext();)
194            {
195                SubModuleDescriptor smd = (SubModuleDescriptor) i.next();
196    
197                Resource descriptorResource = smd.getDescriptor();
198    
199                if (descriptorResource.getResourceURL() == null)
200                {
201                    _errorHandler.error(
202                            LOG,
203                            ImplMessages.subModuleDoesNotExist(descriptorResource),
204                            smd.getLocation(),
205                            null);
206                    continue;
207                }
208    
209                processResource(smd.getDescriptor());
210            }
211        }
212    
213        protected XmlResourceProcessor getResourceProcessor(ClassResolver resolver, ErrorHandler handler)
214        {
215            return new XmlResourceProcessor(resolver, handler);
216        }
217    }