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.ant;
016
017 import java.io.BufferedOutputStream;
018 import java.io.File;
019 import java.io.FileOutputStream;
020 import java.io.IOException;
021 import java.io.OutputStream;
022 import java.net.URL;
023 import java.util.ArrayList;
024 import java.util.List;
025
026 import org.apache.hivemind.ModuleDescriptorProvider;
027 import org.apache.hivemind.Resource;
028 import org.apache.hivemind.impl.DefaultClassResolver;
029 import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
030 import org.apache.hivemind.util.FileResource;
031 import org.apache.hivemind.util.URLResource;
032 import org.apache.tools.ant.BuildException;
033 import org.apache.tools.ant.Task;
034 import org.apache.tools.ant.types.Path;
035 import org.apache.xml.serialize.OutputFormat;
036 import org.apache.xml.serialize.XMLSerializer;
037 import org.w3c.dom.Document;
038
039 /**
040 * Reads some number of hivemodule deployment descriptors (specified as a fileset) and builds a
041 * composite registry by simply concatinating them all. The resulting file is suitable for passing
042 * through an XSLT processor to create documentation.
043 * <p>
044 * The resulting XML file does not conform to the hivemind module deployment descriptor schema. The
045 * following changes occur:
046 * <ul>
047 * <li>The outermost element is <registry> (which contains a list of <module>)
048 * <li>A unique id (unique within the file) is assigned to each <module>,
049 * <configuration-point>, <service-point>, <contribution>, &tl;schema> and
050 * <implementation> (this is to make it easier to generate links and anchors)
051 * <li>Unqualified ids are converted to qualified ids (whereever possible).
052 * </ul>
053 *
054 * @author Howard Lewis Ship
055 */
056 public class ConstructRegistry extends Task
057 {
058 private File _output;
059
060 private Path _descriptorsPath;
061
062 /**
063 * List of {@link org.apache.hivemind.Resource} of additional descriptors to parse.
064 */
065 private List _resourceQueue = new ArrayList();
066
067 public void execute() throws BuildException
068 {
069 if (_output == null)
070 throw new BuildException("You must specify an output file");
071
072 if (_descriptorsPath == null)
073 throw new BuildException("You must specify a set of module descriptors");
074
075 long outputStamp = _output.lastModified();
076
077 String[] paths = _descriptorsPath.list();
078 int count = paths.length;
079
080 boolean needsUpdate = false;
081
082 File[] descriptors = new File[count];
083
084 for (int i = 0; i < count; i++)
085 {
086 File f = new File(paths[i]);
087
088 if (f.isDirectory())
089 continue;
090
091 if (f.lastModified() > outputStamp)
092 needsUpdate = true;
093
094 descriptors[i] = f;
095 }
096
097 if (needsUpdate)
098 {
099 Document registry = constructRegistry(descriptors);
100
101 log("Writing registry to " + _output);
102
103 writeDocument(registry, _output);
104 }
105
106 }
107
108 private Document constructRegistry(File[] moduleDescriptors) throws BuildException
109 {
110 try
111 {
112 enqueue(moduleDescriptors);
113
114 ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(
115 new DefaultClassResolver(), _resourceQueue);
116
117 RegistrySerializer generator = new RegistrySerializer();
118
119 generator.addModuleDescriptorProvider(provider);
120
121 Document result = generator.createRegistryDocument();
122
123 return result;
124 }
125 catch (Exception ex)
126 {
127 throw new BuildException(ex);
128 }
129 }
130
131 private void enqueue(File[] descriptors) throws IOException
132 {
133 for (int i = 0; i < descriptors.length; i++)
134 enqueue(descriptors[i]);
135 }
136
137 /**
138 * Queues up a single descriptor which may be a raw XML file, or a JAR (containing the XML
139 * file).
140 */
141 private void enqueue(File file) throws IOException
142 {
143 // This occurs when a bare directory is part of the classpath.
144
145 if (file == null)
146 return;
147
148 if (file.getName().endsWith(".jar"))
149 {
150 enqueueJar(file);
151 return;
152 }
153
154 String path = file.getPath().replace('\\', '/');
155
156 Resource r = new FileResource(path);
157
158 enqueue(r);
159 }
160
161 private void enqueue(Resource resource)
162 {
163 if (!_resourceQueue.contains(resource))
164 _resourceQueue.add(resource);
165 }
166
167 private void enqueueJar(File jarFile) throws IOException
168 {
169 URL jarRootURL = new URL("jar:" + jarFile.toURL() + "!/");
170
171 Resource jarResource = new URLResource(jarRootURL);
172
173 enqueueIfExists(jarResource, XmlModuleDescriptorProvider.HIVE_MODULE_XML);
174 }
175
176 private void enqueueIfExists(Resource jarResource, String path)
177 {
178 Resource r = jarResource.getRelativeResource(path);
179
180 if (r.getResourceURL() != null)
181 enqueue(r);
182 }
183
184 private void writeDocument(Document document, File file) throws BuildException
185 {
186 try
187 {
188 OutputStream out = new FileOutputStream(file);
189 BufferedOutputStream buffered = new BufferedOutputStream(out);
190
191 writeDocument(document, buffered);
192
193 buffered.close();
194 }
195 catch (IOException ex)
196 {
197 throw new BuildException(
198 "Unable to write registry to " + file + ": " + ex.getMessage(), ex);
199 }
200 }
201
202 private void writeDocument(Document document, OutputStream out) throws IOException
203 {
204 XMLSerializer serializer = new XMLSerializer(out, new OutputFormat(document, null, true));
205 serializer.serialize(document);
206 }
207
208 public Path createDescriptors()
209 {
210 _descriptorsPath = new Path(getProject());
211 return _descriptorsPath;
212 }
213
214 public File getOutput()
215 {
216 return _output;
217 }
218
219 public void setOutput(File file)
220 {
221 _output = file;
222 }
223
224 }