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 }