View Javadoc

1   /*
2    * This file is part of hyphenType. hyphenType is free software: you can
3    * redistribute it and/or modify it under the terms of the GNU General Public
4    * License as published by the Free Software Foundation, either version 3 of the
5    * License, or (at your option) any later version. hyphenType is distributed in
6    * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
8    * the GNU General Public License for more details. You should have received a
9    * copy of the GNU General Public License along with hyphenType. If not, see
10   * <http://www.gnu.org/licenses/>.
11   */
12  package org.hyphenType.documentation;
13  
14  import java.io.PrintStream;
15  import java.lang.annotation.Annotation;
16  import java.lang.reflect.Constructor;
17  import java.lang.reflect.InvocationTargetException;
18  import java.lang.reflect.Method;
19  import java.util.MissingResourceException;
20  import java.util.ResourceBundle;
21  
22  import org.hyphenType.datastructure.Options;
23  import org.hyphenType.datastructure.annotations.ArgumentsObject;
24  import org.hyphenType.exceptions.InvalidOptionsInterfaceException;
25  import org.hyphenType.exit.ExitStatusConstant;
26  import org.hyphenType.lexerparser.LexerParser;
27  import org.hyphenType.util.DefaultAnnotation;
28  import org.hyphenType.util.I18NResourceBundle;
29  import org.hyphenType.util.soc.StringObjectConversion;
30  import org.hyphenType.util.soc.StringParsingError;
31  
32  /**
33   * @author Aurelio Akira M. Matsui
34   * @param <T>
35   *            TODO
36   * @param <V>
37   *            TODO
38   */
39  public abstract class DocumentationFormatterEngine<T extends Options<?>, V extends Annotation> {
40  
41      /**
42       * 
43       */
44      private LexerParser<T> lexPar;
45      /**
46       * 
47       */
48      private V annotation;
49      /**
50       * 
51       */
52      private ResourceBundle rb;
53  
54      /**
55       * 
56       */
57      protected DocumentationFormatterEngine() {
58      }
59  
60      /**
61       * @param lexerParser
62       *            TODO
63       */
64      private void setLexerParser(final LexerParser<T> lexerParser) {
65          lexPar = lexerParser;
66      }
67  
68      /**
69       * @param formatterAnnotation
70       *            TODO
71       */
72      private void setAnnotation(final V formatterAnnotation) {
73          annotation = formatterAnnotation;
74          // TODO Check if the annotation was correctly declared.
75      }
76  
77      /**
78       * @param resourceBundle
79       *            TODO
80       */
81      private void setResourceBundle(final ResourceBundle resourceBundle) {
82          rb = resourceBundle;
83      }
84  
85      /**
86       * @return TODO
87       */
88      public final V getAnnotation() {
89          return annotation;
90      }
91  
92      /**
93       * @param key
94       *            TODO
95       * @param defaultValue
96       *            TODO
97       * @return TODO
98       */
99      public final String getMessage(final String key, final String defaultValue) {
100         try {
101             return rb.getString(key);
102         } catch (MissingResourceException e) {
103             return defaultValue;
104         }
105     }
106 
107     /**
108      * Prints the documentation to the default stdout (System.out).
109      */
110     public final void printDocumentation() {
111         printDocumentation(System.out, lexPar, annotation);
112     }
113 
114     /**
115      * Prints the documentation to the given {@link PrintStream}. Tip: A very
116      * convenient way to save the output to a file is to call
117      * 
118      * <pre>
119      * <code>
120      * printDocumentation(new PrintStream("file.name"));
121      * </code>
122      * </pre>
123      * 
124      * @param pw
125      *            TODO
126      */
127     public final void printDocumentation(final PrintStream pw) {
128         printDocumentation(pw, lexPar, annotation);
129         pw.flush();
130     }
131 
132     /**
133      * @param pw
134      *            TODO
135      * @param parser
136      *            TODO
137      * @param formatterAnnotation
138      *            TODO
139      */
140     protected abstract void printDocumentation(PrintStream pw, LexerParser<T> parser, V formatterAnnotation);
141 
142     /**
143      * Retrieves messages from the resource bundles.
144      * 
145      * @param key
146      *            TODO
147      * @param defaultValue
148      *            TODO
149      * @return TODO
150      * @throws StringParsingError
151      *             TODO
152      */
153     protected final String getOptionsInterfaceValue(final String key, final String defaultValue) throws StringParsingError {
154         String result = getOptionsInterfaceValue(key);
155         if (result == null) {
156             return defaultValue;
157         }
158         return result;
159     }
160 
161     /**
162      * Retrieves messages from the resource bundles.
163      * 
164      * @param key
165      *            TODO
166      * @return TODO
167      * @throws StringParsingError
168      *             TODO
169      */
170     protected final String getOptionsInterfaceValue(final String key) throws StringParsingError {
171         String rbKey;
172         if (key.equals("")) {
173             rbKey = lexPar.getOptionsInterface().getName();
174         } else {
175             rbKey = lexPar.getOptionsInterface().getName() + "." + key;
176         }
177 
178         if (rb.containsKey(rbKey)) {
179             return rb.getString(rbKey);
180         } else {
181             return null;
182         }
183     }
184 
185     /**
186      * @param key
187      *            TODO
188      * @return TODO
189      * @throws StringParsingError
190      *             TODO
191      */
192     protected final String getStatusCodeUserDescription(final Enum<?> statusCode) throws StringParsingError {
193         
194         ExitStatusConstant exitStatusDocumentation = DefaultAnnotation.getAnnotation(statusCode, ExitStatusConstant.class);
195         DefaultAnnotation.fillWithResourceBundle(exitStatusDocumentation, rb);
196         
197         if(exitStatusDocumentation.userDescription()==null || exitStatusDocumentation.userDescription().equals("")) {
198             return statusCode.toString();
199         } else {
200             return exitStatusDocumentation.userDescription();
201         }
202     }
203 
204     /**
205      * Builds the preferred formatter. Either the one that is default for the
206      * options interface; the one chosen by the options interface user, which
207      * can be configured using properties files; or the default formatter, which
208      * is the default value of the property
209      * {@link ArgumentsObject#preferredDocumentationFormatter()}.
210      * 
211      * @param optionsInterface
212      *            TODO
213      * @return TODO
214      */
215     @SuppressWarnings("unchecked")
216     public static DocumentationFormatterEngine preferredFormatter(final Class<? extends Options<?>> optionsInterface) {
217 
218         /*
219          * Note: Originally, this method's signature was public static <R
220          * extends Options> DocumentationFormatterEngine<R>
221          * preferredFormatter(Class<R> optionsInterface) But there seems to be a
222          * difference between the compiler of JDK6 and the one used by Eclipse.
223          * So for now we will utilize the (poorer) alternative: public static
224          * DocumentationFormatterEngine preferredFormatter(Class
225          * optionsInterface)
226          */
227 
228         ArgumentsObject ao = DefaultAnnotation.getAnnotation(optionsInterface, ArgumentsObject.class);
229         Class<? extends Annotation> formatterAnnotationClass = (Class<? extends Annotation>) ao.preferredDocumentationFormatter();
230         return buildFormatter(optionsInterface, formatterAnnotationClass);
231     }
232 
233     /**
234      * Builds a formatter based on the options interface and the formatter
235      * annotation. Documentation formatters are referenced by their annotation,
236      * instead of its class.
237      * 
238      * @param <A>
239      *            The options interface class.
240      * @param <B>
241      *            The documentation formatter annotation.
242      * @param optionsInterface
243      *            The options interface class.
244      * @param formatterAnnotationClass
245      *            The documentation formatter annotation.
246      * @return A new documentation formatter.
247      */
248     @SuppressWarnings("unchecked")
249     public static <A extends Options<?>, B extends Annotation> DocumentationFormatterEngine<A, B> buildFormatter(final Class<A> optionsInterface, final Class<B> formatterAnnotationClass) {
250 
251         Class<? extends DocumentationFormatterEngine<A, B>> formatterClass = (Class<? extends DocumentationFormatterEngine<A, B>>) formatterAnnotationClass.getEnclosingClass();
252 
253         try {
254 
255             B annotationObj = DefaultAnnotation.getAnnotation(optionsInterface, formatterAnnotationClass);
256             ResourceBundle rb = new I18NResourceBundle(optionsInterface);
257 
258             for (Method m : formatterAnnotationClass.getMethods()) {
259                 if (m.getDeclaringClass().equals(formatterAnnotationClass)) {
260 
261                     if (rb.containsKey(formatterAnnotationClass.getName() + "." + m.getName())) {
262                         try {
263                             DefaultAnnotation.set(annotationObj, m, StringObjectConversion.fromString(m.getReturnType(), rb.getString(formatterAnnotationClass.getName() + "." + m.getName())));
264                         } catch (StringParsingError e) {
265                             // TODO Auto-generated catch block
266                             e.printStackTrace();
267                         }
268                     } else {
269                         if (m.invoke(annotationObj) != null) {
270                             DefaultAnnotation.set(annotationObj, m, m.invoke(annotationObj));
271                         }
272                     }
273                 } else {
274                     if (m.getDefaultValue() != null) {
275                         DefaultAnnotation.set(annotationObj, m, m.getDefaultValue());
276                     }
277                 }
278             }
279 
280             Constructor<DocumentationFormatterEngine<A, B>> constructor = (Constructor<DocumentationFormatterEngine<A, B>>) formatterClass.getConstructor();
281             DocumentationFormatterEngine<A, B> engine = constructor.newInstance();
282             engine.setLexerParser(new LexerParser(optionsInterface));
283             engine.setAnnotation(annotationObj);
284             engine.setResourceBundle(rb);
285             return engine;
286 
287         } catch (SecurityException e) {
288             // TODO Auto-generated catch block
289             e.printStackTrace();
290         } catch (NoSuchMethodException e) {
291             // TODO Auto-generated catch block
292             e.printStackTrace();
293         } catch (IllegalArgumentException e) {
294             // TODO Auto-generated catch block
295             e.printStackTrace();
296         } catch (InstantiationException e) {
297             // TODO Auto-generated catch block
298             e.printStackTrace();
299         } catch (IllegalAccessException e) {
300             // TODO Auto-generated catch block
301             e.printStackTrace();
302         } catch (InvocationTargetException e) {
303             // TODO Auto-generated catch block
304             e.printStackTrace();
305         } catch (InvalidOptionsInterfaceException e) {
306             // TODO Auto-generated catch block
307             e.printStackTrace();
308         }
309         return null;
310     }
311 }