View Javadoc

1   /*
2    * $Id: SchemaDocsMain.java 11248 2008-03-07 13:41:25Z acooke $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.tools.schemadocs;
12  
13  import org.mule.util.IOUtils;
14  
15  import java.io.File;
16  import java.io.FileOutputStream;
17  import java.io.FilenameFilter;
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.io.OutputStreamWriter;
22  import java.net.JarURLConnection;
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.util.Arrays;
26  import java.util.Enumeration;
27  import java.util.Iterator;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.jar.JarEntry;
31  
32  import javax.xml.parsers.ParserConfigurationException;
33  import javax.xml.transform.Source;
34  import javax.xml.transform.Templates;
35  import javax.xml.transform.Transformer;
36  import javax.xml.transform.TransformerException;
37  import javax.xml.transform.TransformerFactory;
38  import javax.xml.transform.stream.StreamResult;
39  import javax.xml.transform.stream.StreamSource;
40  
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  import org.springframework.core.io.Resource;
44  import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
45  
46  
47  public class SchemaDocsMain
48  {
49  
50      public static final String BACKUP = ".bak";
51      public static final String XSD = ".xsd";
52      public static final String MULE = "mule";
53      public static final String TAG = "tag";
54      public static final String XSL_FILE = "rename-tag.xsl";
55      public static final List TARGET_PATH = Arrays.asList(new String[]{"tools", "schemadocs", "target"});
56      public static final String[] BLOCKED = new String[]{"wssecurity"};
57  
58      protected final Log logger = LogFactory.getLog(getClass());
59  
60      public static void main(String[] args)
61              throws IOException, TransformerException, ParserConfigurationException
62      {
63          if (null == args || args.length != 3)
64          {
65              throw new IllegalArgumentException("Needs 3 arguments: prefix, postfix and destination");
66          }
67          new SchemaDocsMain(args[0], args[1], args[2]);
68      }
69  
70      public SchemaDocsMain(String prefix, String postfix, String normalizedPath)
71              throws IOException, TransformerException, ParserConfigurationException
72      {
73          logger.info("Generating " + normalizedPath);
74          logger.debug("prefix: " + prefix);
75          logger.debug("postfix: " + postfix);
76          File normalized = inTargetDir(normalizedPath);
77          backup(normalized);
78          InputStream xslSource = IOUtils.getResourceAsStream(XSL_FILE, getClass());
79          if (null == xslSource)
80          {
81              throw new IllegalStateException("Cannot open " + XSL_FILE);
82          }
83          create(normalized, false);
84          OutputStream out = new FileOutputStream(normalized);
85          logger.debug("out: " + out);
86          OutputStreamWriter outWriter = new OutputStreamWriter(out);
87          IOUtils.copy(IOUtils.getResourceAsStream(prefix, getClass()), outWriter);
88          outWriter.flush();
89          processSchema(xslSource, out);
90          out.flush();
91          IOUtils.copy(IOUtils.getResourceAsStream(postfix, getClass()), outWriter);
92          outWriter.close();
93      }
94  
95      protected void create(File file, boolean dir) throws IOException
96      {
97          if (!file.getParentFile().exists())
98          {
99              create(file.getParentFile(), true);
100         }
101         logger.debug("creating " + file);
102         if (dir)
103         {
104             file.mkdir();
105         }
106         else
107         {
108             file.createNewFile();
109         }
110     }
111 
112     // if possible, and path not absolute, place in target directory
113     protected File inTargetDir(String path)
114     {
115         if (path.startsWith(File.separator))
116         {
117             return new File(path);
118         }
119         else
120         {
121             File dir = new File(".");
122             Iterator dirs = TARGET_PATH.iterator();
123             boolean foundPath = false;
124             while (dirs.hasNext())
125             {
126                 File next = new File(dir, (String) dirs.next());
127                 if (next.exists())
128                 {
129                     foundPath = true;
130                     dir = next;
131                 }
132                 else if (foundPath)
133                 {
134                     // in this case we started down the path, but failed
135                     // (this avoids us placing the file somewhere other than "target"
136                     // to workaround, specify absolute path)
137                     throw new IllegalArgumentException("Could not find " + next + " while placing in target directory");
138                 }
139             }
140             File target = new File(dir, path);
141             logger.info("Target: " + target);
142             return target;
143         }
144     }
145 
146     protected void processSchema(InputStream xslSource, OutputStream out)
147             throws TransformerException, IOException, ParserConfigurationException
148     {
149         TransformerFactory factory = TransformerFactory.newInstance();
150         Templates template = factory.newTemplates(new StreamSource(xslSource));
151         Transformer xformer = template.newTransformer();
152         Iterator urls = listSchema2().iterator();
153         while (urls.hasNext())
154         {
155             URL url = (URL) urls.next();
156             String tag = tagFromFileName(url.getFile());
157             logger.info(tag + " : " + url);
158             xformer.setParameter(TAG, tag);
159             Source source = new StreamSource(url.openStream());
160             xformer.transform(source, new StreamResult(out));
161 //            xformer.transform(source, new StreamResult(System.out));
162             out.flush();
163         }
164     }
165 
166     // this avoids using File objects since we may be dealing with classpath jars etc etc
167     protected static String tagFromFileName(String name)
168     {
169         String dropExtension = toLeftOf(name, ".", name);
170         String dropSlash = toRightOf(dropExtension, "/", dropExtension, true);
171         String dropBackslash = toRightOf(dropSlash, "\\", dropSlash, true);
172         return toRightOf(dropBackslash, "-", "mule", false);
173     }
174 
175     protected static String toRightOf(String text, String delim, String deflt, boolean far)
176     {
177         int index = far ? text.lastIndexOf(delim) : text.indexOf(delim);
178         if (index > -1)
179         {
180             return text.substring(index+1);
181         }
182         else
183         {
184             return deflt;
185         }
186     }
187 
188     protected static String toLeftOf(String text, String delim, String deflt)
189     {
190         int index = text.lastIndexOf(delim);
191         if (index > -1)
192         {
193             return text.substring(0, index);
194         }
195         else
196         {
197             return deflt;
198         }
199     }
200 
201     // for some reason, this doesn't work
202     protected List listSchema1() throws IOException
203     {
204         PathMatchingResourcePatternResolver resolver =
205                 new PathMatchingResourcePatternResolver(getClass().getClassLoader());
206         Resource[] resources = resolver.getResources("**/META-INF/*.xsd");
207         List list = new LinkedList();
208         for (int i = 0; i < resources.length; ++i)
209         {
210             list.add(resources[i].getURL());
211         }
212         return list;
213     }
214 
215     // this is a bit ad-hoc, but seems to work efficiently
216     // http://forum.java.sun.com/thread.jspa?threadID=286026&messageID=1119510
217     protected List listSchema2() throws IOException
218     {
219         ClassLoader loader = getClass().getClassLoader();
220         List files = new LinkedList();
221         Enumeration resources = loader.getResources("META-INF");
222         FilenameFilter filter =
223                 new FilenameFilter() {
224                     public boolean accept(File dir, String name)
225                     {
226                         if (name.startsWith(MULE) && name.endsWith(XSD))
227                         {
228                             for (int i = 0; i < BLOCKED.length; ++i)
229                             {
230                                 if (name.indexOf(BLOCKED[i]) > -1)
231                                 {
232                                     return false;
233                                 }
234                             }
235                             return true;
236                         }
237                         else
238                         {
239                             return false;
240                         }
241                     }
242                 };
243         while (resources.hasMoreElements())
244         {
245             URL url = (URL) resources.nextElement();
246             logger.debug("url: " + url);
247             if (url.toString().startsWith("jar:"))
248             {
249                 readFromJar(url, files);
250             }
251             else if ("file".equals(url.getProtocol()))
252             {
253                 readFromDirectory(new File(url.getFile()), files, filter);
254             }
255         }
256         return files;
257     }
258 
259     // this is used from within idea
260     protected void readFromDirectory(File dir, List files, FilenameFilter filter) throws MalformedURLException
261     {
262         String[] names = dir.list(filter);
263         for (int i = 0; i < names.length; ++i)
264         {
265             String name = names[i];
266             logger.debug("file: " + name);
267             files.add(new File(dir, name).toURL());
268         }
269     }
270 
271     // this is used from within maven
272     protected void readFromJar(URL jarUrl, List resources) throws IOException
273     {
274         JarURLConnection jarConnection = (JarURLConnection) jarUrl.openConnection();
275         Enumeration entries = jarConnection.getJarFile().entries();
276         while (entries.hasMoreElements())
277         {
278             JarEntry entry = (JarEntry) entries.nextElement();
279             String name = new File(entry.getName()).getName();
280             if (name.startsWith(MULE) && name.endsWith(XSD))
281             {
282                 logger.debug("entry: " + entry);
283                 resources.add(new URL(jarUrl, entry.getName()));
284             }
285         }
286   }
287 
288     protected void backup(File file) throws IOException
289     {
290         if (file.exists())
291         {
292             File backup = new File(file.getAbsoluteFile().getParent(), file.getName() + BACKUP);
293             if (backup.exists())
294             {
295                 logger.debug("deleting " + backup.getCanonicalPath());
296                 backup.delete();
297             }
298             logger.debug("renaming " + file.getCanonicalPath() + " to " + backup.getCanonicalPath());
299             file.renameTo(backup);
300         }
301     }
302 
303 }