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 }