View Javadoc

1   package no.sesat.mojo.modes;
2   
3   import static com.sun.tools.javac.code.Flags.PROTECTED;
4   import static com.sun.tools.javac.code.Flags.PUBLIC;
5   
6   import java.io.ByteArrayOutputStream;
7   import java.io.File;
8   import java.io.IOException;
9   import java.io.PrintStream;
10  import java.util.Vector;
11  
12  import com.sun.javadoc.ClassDoc;
13  import com.sun.javadoc.RootDoc;
14  import com.sun.tools.javac.util.Context;
15  import com.sun.tools.javac.util.ListBuffer;
16  import com.sun.tools.javac.util.Options;
17  import com.sun.tools.javadoc.JavadocTool;
18  import com.sun.tools.javadoc.Messager;
19  import com.sun.tools.javadoc.ModifierFilter;
20  import com.sun.tools.javadoc.RootDocImpl;
21  
22  /**
23   * Builder to build a structure that mirrors the structure that should be used
24   * in the modes.xml files. *
25   */
26  public final class Builder {
27  
28      private static String outputDir = "";
29      private static String id = "";
30  
31      private Builder() {
32      }
33  
34      /**
35       * Build and generate schema for modes.xml files.
36       *
37       * @param classpath
38       *            Where to find the classes
39       * @param dir
40       *            Where the results should be put
41       * @param idString
42       *            Id
43       */
44      public static void build(final String classpath, final String dir, final String idString) {
45          outputDir = new File(dir).getAbsolutePath() + File.separator;
46          id = idString;
47          RootDocImpl root = null;
48          
49          // hack to suppress javadoc's warnings.
50          final PrintStream out = System.out;
51          final PrintStream err = System.err;
52          try {
53              System.setOut(new PrintStream(new ByteArrayOutputStream()));
54              System.setErr(new PrintStream(new ByteArrayOutputStream()));
55  
56              final Context context = new Context();
57              Messager.preRegister(context, "Builder");
58              final JavadocTool comp = JavadocTool.make0(context);
59  
60              final ListBuffer<String> subPackages = new ListBuffer<String>();
61              subPackages.append("no");
62              final ListBuffer<String> xcludePackages = new ListBuffer<String>();
63              final ListBuffer<String> javaNames = new ListBuffer<String>();
64              final ListBuffer<String[]> options = new ListBuffer<String[]>();
65  
66              final Options compOpts = Options.instance(context);
67              compOpts.put("-classpath", classpath);
68              
69              try {
70                  root = comp.getRootDocImpl("", "", new ModifierFilter(PUBLIC | PROTECTED), javaNames.toList(), options
71                          .toList(), false, subPackages.toList(), xcludePackages.toList(), false, false, false);
72              } catch (IOException e) {
73                  e.printStackTrace(err);
74                  return;
75              }
76          } catch (Throwable e) {
77              // e.printStackTrace(out);
78              out.print("Generating schema files failed due to error: " + e.getMessage());
79          } finally {
80              System.setOut(out);
81              System.setErr(err);
82          }
83          if (root != null) {
84              start(root);
85          }
86      }
87  
88      /**
89       * This is the entry point for a doclet.
90       *
91       * @param root
92       *            Root document
93       * @return true when everything is ok
94       */
95      public static boolean start(final RootDoc root) {
96          final ConfigElement defaultConvert = new ConfigElement("default-convert");
97          defaultConvert.attributes.add(new ConfigAttribute("name"));
98          defaultConvert.attributes.add(new ConfigAttribute("prefix"));
99          defaultConvert.attributes.add(new ConfigAttribute("postfix"));
100 
101         final Vector<ConfigElement> commands = new Vector<ConfigElement>();
102         final Vector<ConfigElement> resultHandlers = new Vector<ConfigElement>();
103         final Vector<ConfigElement> queryTransformers = new Vector<ConfigElement>();
104         {
105             final ClassDoc[] classes = root.classes();
106             for (int i = 0; i < classes.length; i++) {
107                 final String name = classes[i].name();
108                 if (name.endsWith("Config") && !classes[i].isAbstract()) {
109                     final ConfigElement element = new ConfigElement(classes[i]);
110 
111                     if (name.endsWith("CommandConfig")) {
112                         element.applyNameFilter(new NameFilter() {
113                             public String filter(final String name) {
114                                 return toXmlName(name.substring(0, name.lastIndexOf("Config")));
115                             }
116                         });
117                         commands.add(element);
118                     } else if (name.endsWith("ResultHandlerConfig")) {
119                         element.applyNameFilter(new NameFilter() {
120                             public String filter(final String name) {
121                                 return toXmlName(name.substring(0, name.lastIndexOf("ResultHandlerConfig")));
122                             }
123                         });
124                         if (!element.name.isEmpty()) {
125                             resultHandlers.add(element);
126                         }
127                     } else if (name.endsWith("QueryTransformer") || (name.endsWith("QueryTransformerConfig"))) {
128                         element.applyNameFilter(new NameFilter() {
129                             public String filter(final String name) {
130                                 return toXmlName(name.substring(0, name.lastIndexOf("QueryTransformer")));
131                             }
132                         });
133 
134                         if (name.equals("NewsCaseQueryTransformerConfig")) {
135                             element.addChild(defaultConvert);
136                         }
137 
138                         queryTransformers.add(element);
139                     } else {
140                         System.out.println("Lost: " + element.name);
141                     }
142                 }
143             }
144         }
145 
146         final ConfigElement modes = new ConfigElement("modes");
147         modes.attributes.add(new ConfigAttribute("template-prefix"));
148 
149         final ConfigElement mode = new ConfigElement("mode");
150         mode.attributes.add(new ConfigAttribute("id"));
151         mode.attributes.add(new ConfigAttribute("inherit"));
152         mode.attributes.add(new ConfigAttribute("analysis"));
153         mode.attributes.add(new ConfigAttribute("executor"));
154 
155         mode.addChildren(commands);
156         modes.addChild(mode);
157 
158         final ConfigElement resultHandler = new ConfigElement("result-handlers");
159         resultHandler.addChildren(resultHandlers);
160 
161         final ConfigElement queryTransform = new ConfigElement("query-transformers");
162         queryTransform.addChildren(queryTransformers);
163 
164         final ConfigElement navigators = new ConfigElement("navigators");
165         final ConfigElement navigator = new ConfigElement("navigator");
166         navigator.attributes.add(new ConfigAttribute("id", null, true));
167         navigator.attributes.add(new ConfigAttribute("name", null, true));
168         navigator.attributes.add(new ConfigAttribute("field", null, true));
169         navigator.attributes.add(new ConfigAttribute("display-name", null, true));
170         navigator.attributes.add(new ConfigAttribute("sort", null, false));
171         navigator.attributes.add(new ConfigAttribute("boundary-match"));
172 
173         // allow recursive nesting of navigator.
174         navigator.addChild(navigator);
175 
176         // only for fast commands
177         navigators.addChild(navigator);
178 
179         for (ConfigElement command : commands) {
180             command.addChild(resultHandler);
181             command.addChild(queryTransform);
182             command.addChild(navigators);
183         }
184 
185         final Runnable[] jobs = {new GenerateRelaxNG(modes, outputDir + "modes.rnc", id),
186                 new GenerateXSD(modes, outputDir + "modes.xsd", id),
187                 new GenerateDTD(modes, outputDir + "modes.dtd", id)};
188         final int jobCount = 5;
189         for (int i = 0; i < (jobs.length + jobCount - 1); i++) {
190 
191             if (i < jobs.length) {
192                 // System.out.println("start job: " + i);
193                 final Thread thread = new Thread(jobs[i]);
194                 thread.start();
195                 jobs[i] = thread;
196             }
197             if (i >= (jobCount - 1)) {
198                 try {
199                     ((Thread) jobs[i - jobCount + 1]).join();
200                     // System.out.println("job done: " + (i - jobCount + 1));
201                 } catch (InterruptedException e) {
202                     e.printStackTrace();
203                 }
204             }
205         }
206 
207         System.out.println("commands : " + commands.size());
208         System.out.println("result handlers : " + resultHandlers.size());
209         System.out.println("query transformers : " + queryTransformers.size());
210 
211         return true;
212     }
213 
214     /**
215      * Helper function to convert a java name to the equivalent XML name.
216      *
217      * @param name
218      *            Name that should be converted
219      * @return The name converted like this MySuperClass --> my-super-class
220      */
221     public static String toXmlName(final String name) {
222         final StringBuilder xmlName = new StringBuilder(name);
223         for (int i = 0; i < xmlName.length(); ++i) {
224             final char c = xmlName.charAt(i);
225             if (Character.isUpperCase(c)) {
226                 xmlName.replace(i, i + 1, (i == 0 ? "" : "-") + Character.toLowerCase(c));
227                 ++i;
228             }
229         }
230         return xmlName.toString();
231     }
232 }