1 package org.hyphenType.documentation.rbgenerator;
2
3 import static org.hyphenType.exit.CanonicalExitCode.ERROR;
4 import static org.hyphenType.exit.CanonicalExitCode.SUCCESS;
5
6 import java.io.BufferedOutputStream;
7 import java.io.ByteArrayOutputStream;
8 import java.io.File;
9 import java.io.FileNotFoundException;
10 import java.io.FileOutputStream;
11 import java.io.IOException;
12 import java.io.OutputStream;
13 import java.io.PrintWriter;
14 import java.lang.annotation.Annotation;
15 import java.lang.reflect.InvocationTargetException;
16 import java.lang.reflect.Method;
17 import java.text.DateFormat;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Date;
21 import java.util.List;
22
23 import org.hyphenType.datastructure.annotations.ArgumentsObject;
24 import org.hyphenType.datastructure.annotations.Option;
25 import org.hyphenType.datastructure.annotations.OptionValue;
26 import org.hyphenType.datastructure.annotations.SimpleArgument;
27 import org.hyphenType.datastructure.parser.option.StructureOption;
28 import org.hyphenType.datastructure.parser.option.StructureOptionArgument;
29 import org.hyphenType.datastructure.parser.simple.StructureSimpleArgument;
30 import org.hyphenType.documentation.Description;
31 import org.hyphenType.documentation.DocumentationFormatterEngine;
32 import org.hyphenType.exceptions.InvalidOptionsInterfaceException;
33 import org.hyphenType.exit.ExitStatusConstant;
34 import org.hyphenType.lexerparser.LexerParser;
35 import org.hyphenType.lexerparser.exceptions.MandatoryMapValueNotFoundException;
36 import org.hyphenType.lexerparser.exceptions.MandatorySimpleArgumentNotFoundException;
37 import org.hyphenType.lexerparser.exceptions.MandatoryValueNotFoundException;
38 import org.hyphenType.lexerparser.exceptions.RegexMismatchException;
39 import org.hyphenType.lexerparser.exceptions.StringParseException;
40 import org.hyphenType.lexerparser.exceptions.StringParsingErrorException;
41 import org.hyphenType.optionprocessors.ArgumentsProcessorEngine;
42 import org.hyphenType.util.DefaultAnnotation;
43 import org.hyphenType.wrapper.StandAloneAppWrapper;
44
45 public class RBGenerator extends StandAloneAppWrapper {
46
47 @SuppressWarnings("unchecked")
48 public void main(RBGeneratorOptions args) {
49
50 if (args.h()) {
51 args.printDocumentation();
52 args.exit(SUCCESS);
53 }
54
55 if (args.optionsClass()==null) {
56 System.err.println("No options interface. Giving up. Use --help for more details.");
57 args.exit(ERROR);
58 }
59
60 if (args.f() && args.fileName().equals("")) {
61 System.err.println("You should inform a file name. Giving up. Use --help for more details.");
62 args.exit(ERROR);
63 }
64
65 try {
66
67 LexerParser lexParser = new LexerParser(args.optionsClass(), false);
68 ArgumentsObject argumentsObject = lexParser.getArgsObject();
69
70
71
72
73 ByteArrayOutputStream aliasesBao = new ByteArrayOutputStream();
74 PrintWriter aliasesPw = new PrintWriter(aliasesBao);
75 aliasesPw.println("#");
76 aliasesPw.println("# Aliases");
77 aliasesPw.println("#");
78 aliasesPw.println();
79
80
81
82
83 aliasesPw.println(String.format("alias.ao = %s", ArgumentsObject.class.getName()));
84 ByteArrayOutputStream aoBao = new ByteArrayOutputStream();
85 PrintWriter aoPw = new PrintWriter(aoBao);
86 aoPw.println("#");
87 aoPw.println("# Arguments object");
88 aoPw.println("#");
89 aoPw.println();
90 aoPw.println(String.format("${ao}.description = %s", argumentsObject.description()));
91 aoPw.println(String.format("${ao}.doubleHyphenInLongOptions = %s", argumentsObject.doubleHyphenInLongOptions()));
92 aoPw.println(String.format("${ao}.singleHyphen = %s", argumentsObject.singleHyphen()));
93 aoPw.println(String.format("${ao}.doubleHyphen = %s", argumentsObject.doubleHyphen()));
94 aoPw.println(String.format("${ao}.equals = %s", argumentsObject.equals()));
95 aoPw.println(String.format("${ao}.documentStatusCodes = %s", argumentsObject.documentStatusCodes()));
96 aoPw.println(String.format("${ao}.preferredDocumentationFormatter = %s", argumentsObject.preferredDocumentationFormatter().getName()));
97
98
99
100
101
102 ByteArrayOutputStream processorsBao = new ByteArrayOutputStream();
103 PrintWriter processorsPw = new PrintWriter(processorsBao);
104 processorsPw.println("#");
105 processorsPw.println("# Argument processors");
106 processorsPw.println("#");
107 processorsPw.println();
108 boolean found = false;
109 for (Annotation annotation : args.optionsClass().getAnnotations()) {
110 if (annotation.annotationType().getEnclosingClass() != null && ArgumentsProcessorEngine.class.isAssignableFrom(annotation.annotationType().getEnclosingClass())) {
111 found = true;
112 Class<?> processorAnnotationClass = annotation.annotationType();
113
114
115
116
117 String aliasName = processorAnnotationClass.getSimpleName();
118 aliasesPw.println(String.format("alias.p.%s = %s", aliasName, processorAnnotationClass.getName()));
119 processorsPw.println("# " + annotation.annotationType().getSimpleName());
120 processorsPw.println();
121 for (Method m : processorAnnotationClass.getDeclaredMethods()) {
122 if (m.isAnnotationPresent(Description.class)) {
123 processorsPw.println("# " + m.getAnnotation(Description.class).value());
124 }
125 try {
126 if (m.getReturnType().isArray()) {
127 if (m.getReturnType().getComponentType().isAnnotation()) {
128 processorsPw.print(expandAnnotationArray(String.format("${p.%s}.%s", aliasName, m.getName()), (Annotation[])m.invoke(annotation), m.getReturnType().getComponentType()));
129 } else {
130 processorsPw.println(String.format("${p.%s}.%s = %s", aliasName, m.getName(), Arrays.toString((Object[])m.invoke(annotation))));
131 }
132 } else {
133 processorsPw.println(String.format("${p.%s}.%s = %s", aliasName, m.getName(), m.invoke(annotation)));
134 }
135
136
137 } catch (IllegalArgumentException e) {
138 e.printStackTrace();
139 } catch (IllegalAccessException e) {
140 e.printStackTrace();
141 } catch (InvocationTargetException e) {
142 e.printStackTrace();
143 }
144 }
145 }
146 }
147 if(!found) {
148 processorsPw.println("# No argument processor found");
149 }
150
151
152
153
154 aliasesPw.println("alias.Interface = " + args.optionsClass().getName());
155 aliasesPw.println("alias.Option = " + Option.class.getName());
156 aliasesPw.println("alias.OptionValue = " + OptionValue.class.getName());
157 aliasesPw.println("alias.OptionArgument = " + OptionValue.class.getName());
158 ByteArrayOutputStream optionsBao = new ByteArrayOutputStream();
159 PrintWriter optionsPw = new PrintWriter(optionsBao);
160 optionsPw.println("#");
161 optionsPw.println("# Options");
162 optionsPw.println("#");
163 optionsPw.println();
164 List<StructureOption> options = lexParser.getParsedOptions();
165 for(StructureOption option : options) {
166 optionsPw.println(String.format("${Interface}.%s@${Option}.names = %s", option.method.getName(), option.alternatives));
167 optionsPw.println(String.format("${Interface}.%s@${Option}.description = %s", option.method.getName(), option.description));
168 if(option.value!=null) {
169 optionsPw.println(String.format("${Interface}.%s@${OptionValue}.name = %s", option.value.method.getName(), option.value.name));
170 optionsPw.println(String.format("${Interface}.%s@${OptionValue}.option = %s", option.value.method.getName(), option.method.getName()));
171 optionsPw.println(String.format("${Interface}.%s@${OptionValue}.mandatory = %s", option.value.method.getName(), option.value.mandatory));
172 optionsPw.println(String.format("${Interface}.%s@${OptionValue}.arraySeparator = %s", option.value.method.getName(), option.value.arraySeparator));
173 optionsPw.println(String.format("${Interface}.%s@${OptionValue}.arrayUseFileSeparator = %s", option.value.method.getName(), option.value.arrayUseFileSeparator));
174 }
175 for(StructureOptionArgument argument : option.arguments) {
176 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.name = %s", argument.method.getName(), argument.getName()));
177 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.option = %s", argument.method.getName(), option.method.getName()));
178 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.index = %s", argument.method.getName(), argument.getIndex()));
179 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.regex = %s", argument.method.getName(), argument.getRegex()));
180 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.channels = %s", argument.method.getName(), argument.getChannels()));
181 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.mandatory = %s", argument.method.getName(), argument.isMandatory()));
182 optionsPw.println(String.format("${Interface}.%s@${OptionArgument}.description = %s", argument.method.getName(), argument.getDescription()));
183 }
184 }
185
186
187
188
189 aliasesPw.println("alias.SimpleArgument = " + SimpleArgument.class.getName());
190 ByteArrayOutputStream simpleArgumentsBao = new ByteArrayOutputStream();
191 PrintWriter simpleArgumentsPw = new PrintWriter(simpleArgumentsBao);
192 simpleArgumentsPw.println("#");
193 simpleArgumentsPw.println("# Simple Arguments");
194 simpleArgumentsPw.println("#");
195 simpleArgumentsPw.println();
196
197 List<StructureSimpleArgument> simpleArguments = lexParser.getSimpleArguments();
198 for(StructureSimpleArgument simpleArgument : simpleArguments) {
199 simpleArgumentsPw.println(String.format("${Interface}.%s@${SimpleArgument}.name = %s", simpleArgument.method.getName(), simpleArgument.getName()));
200 simpleArgumentsPw.println(String.format("${Interface}.%s@${SimpleArgument}.index = %s", simpleArgument.method.getName(), simpleArgument.getIndex()));
201 simpleArgumentsPw.println(String.format("${Interface}.%s@${SimpleArgument}.description = %s", simpleArgument.method.getName(), simpleArgument.getDescription()));
202 simpleArgumentsPw.println(String.format("${Interface}.%s@${SimpleArgument}.regex = %s", simpleArgument.method.getName(), simpleArgument.getRegex()));
203 simpleArgumentsPw.println(String.format("${Interface}.%s@${SimpleArgument}.mandatory = %s", simpleArgument.method.getName(), simpleArgument.isMandatory()));
204 simpleArgumentsPw.println(String.format("${Interface}.%s@${SimpleArgument}.channels = %s", simpleArgument.method.getName(), simpleArgument.getChannels()));
205 }
206
207
208
209
210 aliasesPw.println("alias.status = " + argumentsObject.statusCodeEnum().getName());
211 aliasesPw.println("alias.stdoc = " + ExitStatusConstant.class.getName());
212 ByteArrayOutputStream statusBao = new ByteArrayOutputStream();
213 PrintWriter statusPw = new PrintWriter(statusBao);
214 statusPw.println("#");
215 statusPw.println("# Exit status");
216 statusPw.println("#");
217 Class<? extends Enum> statusCodeEnumClass = (Class<? extends Enum>) argumentsObject.statusCodeEnum();
218 for(Enum enumConstant : statusCodeEnumClass.getEnumConstants()) {
219 statusPw.println();
220 try {
221 if(argumentsObject.statusCodeEnum().getField(enumConstant.toString()).isAnnotationPresent(Description.class)) {
222 String description = argumentsObject.statusCodeEnum().getField(enumConstant.toString()).getAnnotation(Description.class).value();
223 description = description.replaceAll("\n", "\n# ");
224 statusPw.println(String.format("# %s", description));
225 }
226
227
228
229
230 } catch (SecurityException e) {
231 e.printStackTrace();
232 } catch (NoSuchFieldException e) {
233 e.printStackTrace();
234 }
235 ExitStatusConstant constant = DefaultAnnotation.getAnnotation((Enum)enumConstant, ExitStatusConstant.class);
236 if(constant.userDescription()==null) {
237 statusPw.println(String.format("${status}.%s@${stdoc}.userDescription = ", enumConstant.toString()));
238 } else {
239 statusPw.println(String.format("${status}.%s@${stdoc}.userDescription = %s", enumConstant.toString(), constant.userDescription()));
240 }
241 if(constant.message()==null) {
242 statusPw.println(String.format("${status}.%s@${stdoc}.message = ", enumConstant.toString()));
243 } else {
244 statusPw.println(String.format("${status}.%s@${stdoc}.message = %s", enumConstant.toString(), constant.message()));
245 }
246
247
248 for (int i = 0; i< constant.catches().length; i++) {
249 statusPw.println(String.format("${status}.%s@${stdoc}.exceptions[%d] = %s", enumConstant.toString(), i, constant.catches()[i].getName()));
250 }
251 }
252
253
254
255
256 ByteArrayOutputStream formatterBao = new ByteArrayOutputStream();
257 PrintWriter formatterPw = new PrintWriter(formatterBao);
258
259 ArrayList<Class<? extends Annotation>> documentationFormattersList = new ArrayList<Class<? extends Annotation>>();
260
261 documentationFormattersList.add(argumentsObject.preferredDocumentationFormatter());
262
263 for (Annotation annotation : args.optionsClass().getAnnotations()) {
264 if (
265 annotation.annotationType().getEnclosingClass()!=null &&
266 DocumentationFormatterEngine.class.isAssignableFrom(annotation.annotationType().getEnclosingClass()) &&
267 !documentationFormattersList.contains(annotation.annotationType())
268 ) {
269 documentationFormattersList.add(annotation.annotationType());
270 }
271 }
272
273 formatterPw.println("#");
274 formatterPw.println("# Documentation formatters");
275 formatterPw.println("#");
276 for (Class<? extends Annotation> formatterClass : documentationFormattersList) {
277
278 aliasesPw.println(String.format("alias.f.%s = %s", formatterClass.getSimpleName(), formatterClass.getName()));
279 formatterPw.println();
280 formatterPw.println("# " + formatterClass.getSimpleName());
281 formatterPw.println();
282
283 Annotation annotation = args.optionsClass().getAnnotation(formatterClass);
284
285 for(Method m : formatterClass.getDeclaredMethods()) {
286 if(m.isAnnotationPresent(Description.class)) {
287 String description = m.getAnnotation(Description.class).value();
288 description = description.replaceAll("\n", "\n# ");
289 formatterPw.println(String.format("# %s", description));
290 }
291
292 if (annotation == null) {
293 if(m.getDefaultValue() == null) {
294 formatterPw.println(String.format("${f.%s}.%s = ", formatterClass.getSimpleName(), m.getName()));
295 } else {
296 formatterPw.println(String.format("${f.%s}.%s = %s", formatterClass.getSimpleName(), m.getName(), m.getDefaultValue()));
297 }
298 } else {
299 try {
300 formatterPw.println(String.format("${f.%s}.%s = %s", formatterClass.getSimpleName(), m.getName(), m.invoke(annotation)));
301
302 } catch (IllegalArgumentException e) {
303 e.printStackTrace();
304 } catch (IllegalAccessException e) {
305 e.printStackTrace();
306 } catch (InvocationTargetException e) {
307 e.printStackTrace();
308 }
309 }
310 }
311 }
312
313
314
315
316
317 ByteArrayOutputStream errorBao = new ByteArrayOutputStream();
318 PrintWriter errorPw = new PrintWriter(errorBao);
319 errorPw.println("#");
320 errorPw.println("# Internal error messages");
321 errorPw.println("#");
322 errorPw.println();
323 errorPw.println(MandatoryMapValueNotFoundException.class.getName() + ".DEFAULT_PATTERN = " + MandatoryMapValueNotFoundException.DEFAULT_PATTERN);
324 errorPw.println(MandatorySimpleArgumentNotFoundException.class.getName() + ".DEFAULT_PATTERN = " + MandatorySimpleArgumentNotFoundException.DEFAULT_PATTERN);
325 errorPw.println(MandatoryValueNotFoundException.class.getName() + ".DEFAULT_PATTERN = " + MandatoryValueNotFoundException.DEFAULT_PATTERN);
326 errorPw.println(RegexMismatchException.class.getName() + ".DEFAULT_PATTERN = " + RegexMismatchException.DEFAULT_PATTERN);
327 errorPw.println(StringParseException.class.getName() + ".DEFAULT_PATTERN = " + StringParseException.DEFAULT_PATTERN);
328 errorPw.println(StringParsingErrorException.class.getName() + ".DEFAULT_PATTERN = " + StringParsingErrorException.DEFAULT_PATTERN);
329
330
331
332
333 aliasesPw.flush();
334 aliasesBao.flush();
335 aoPw.flush();
336 aoBao.flush();
337 processorsPw.flush();
338 processorsBao.flush();
339 optionsPw.flush();
340 optionsBao.flush();
341 simpleArgumentsPw.flush();
342 simpleArgumentsBao.flush();
343 statusPw.flush();
344 statusBao.flush();
345 formatterPw.flush();
346 formatterBao.flush();
347 errorPw.flush();
348 errorBao.flush();
349
350
351
352
353 ArrayList<OutputStream> outputStreams = new ArrayList<OutputStream>();
354 if(args.f()) {
355 String fileNameStem;
356 String fileNameExtension;
357 if(args.fileName().contains(".")) {
358 fileNameStem = args.fileName().substring(0, args.fileName().lastIndexOf('.'));
359 if(args.fileName().endsWith(".")) {
360 fileNameExtension = "properties";
361 }
362 else {
363 fileNameExtension = args.fileName().substring(args.fileName().lastIndexOf('.') + 1);
364 }
365 } else {
366 fileNameStem = args.fileName();
367 fileNameExtension = "properties";
368 outputStreams.add(new FileOutputStream(new File(String.format("%s.%s", fileNameStem, fileNameExtension))));
369 }
370
371 for(String variant : args.supportedLanguages()) {
372 outputStreams.add(new FileOutputStream(new File(String.format("%s_%s.%s", fileNameStem, variant, fileNameExtension))));
373 }
374 } else {
375 outputStreams.add(System.out);
376 }
377
378 for(OutputStream os : outputStreams) {
379 BufferedOutputStream bos = new BufferedOutputStream(os, 1024);
380 PrintWriter pw = new PrintWriter(bos);
381 Date now = new Date();
382 pw.println("# ");
383 pw.println(String.format("# Configuration file for the %s options interface.", args.optionsClass().getName()));
384 pw.println(String.format("# Automatically generated using %s on %s, %s.", RBGenerator.class.getName(), DateFormat.getDateInstance(DateFormat.FULL).format(now), DateFormat.getTimeInstance(DateFormat.FULL).format(now)));
385 pw.println("# ");
386 pw.println();
387 pw.println(aliasesBao.toString());
388 pw.println();
389 pw.println(aoBao.toString());
390 pw.println();
391 pw.println(processorsBao.toString());
392 pw.println();
393 pw.println(optionsBao.toString());
394 pw.println();
395 pw.println(simpleArgumentsBao.toString());
396 pw.println();
397 pw.println(statusBao.toString());
398 pw.println();
399 pw.println(formatterBao.toString());
400 pw.println();
401 pw.println(errorBao.toString());
402 pw.flush();
403 bos.flush();
404 os.flush();
405 os.close();
406 }
407
408 } catch (InvalidOptionsInterfaceException e) {
409
410 e.printStackTrace();
411 } catch (FileNotFoundException e) {
412
413 e.printStackTrace();
414 } catch (IOException e) {
415
416 e.printStackTrace();
417 }
418 }
419
420 public static String expandAnnotationArray(String prefix, Annotation[] array, Class<?> arrayClass) {
421 String result = "";
422 try {
423 int i = 0;
424 for (Annotation annotation : array) {
425
426 for (Method m : arrayClass.getDeclaredMethods()) {
427 if (m.getReturnType().isArray() && m.getReturnType().getComponentType().isAnnotation()) {
428 result += expandAnnotationArray(String.format("%s[%d].%s", prefix, i, m.getName()), (Annotation[]) m.invoke(annotation), m.getReturnType().getComponentType());
429 } else {
430 result += String.format("%s[%d].%s = %s\n", prefix, i, m.getName(), m.invoke(annotation));
431 }
432 }
433 i++;
434 }
435 } catch (IllegalArgumentException e) {
436 e.printStackTrace();
437 } catch (IllegalAccessException e) {
438 e.printStackTrace();
439 } catch (InvocationTargetException e) {
440 e.printStackTrace();
441 }
442 return result;
443 }
444 }