View Javadoc

1   /*
2    * Zemucan: A Syntax Assistant for DB2
3    * Copyright (C) 2009, 2010 Andres Gomez Casanova
4    *
5    * This file is part of Zemucan.
6    *
7    * Zemucan is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as published by
9    * the Free Software Foundation; either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * Zemucan is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public License
18   * along with this library; if not, see <http://www.gnu.org/licenses/>.
19   *
20   * Contact:
21   * a n g o c a  at  y a h o o  dot  c o m
22   * Cra. 45 No 61 - 31, Bogota, Colombia.
23   *
24   * Author:   $LastChangedBy: angoca $:
25   * Date:     $LastChangedDate: 2011-03-06 10:15:32 -0500 (dom, 06 mar 2011) $:
26   * Revision: $LastChangedRevision: 1913 $:
27   * URL:      $HeadURL: https://zemucan.svn.sourceforge.net/svnroot/zemucan/branches/zemucan_v1/source-code/main/src/main/java/name/angoca/zemucan/main/Main.java $:
28   */
29  package name.angoca.zemucan.main;
30  
31  import name.angoca.zemucan.AbstractZemucanException;
32  import name.angoca.zemucan.interfaze.InterfaceCore;
33  import name.angoca.zemucan.tools.configurator.Configurator;
34  import name.angoca.zemucan.ui.api.AbstractInterfaceController;
35  import name.angoca.zemucan.ui.api.InputReaderException;
36  import name.angoca.zemucan.ui.api.SynchronizedLoad;
37  import name.angoca.zemucan.ui.impl.jline.ImplementationJlineInterfaceController;
38  import name.angoca.zemucan.ui.impl.system.ImplementationSystemInterfaceController;
39  
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  /**
44   * This is the class where the application can be started.
45   * <p>
46   * <b>Control Version</b>
47   * <p>
48   * <ul>
49   * <li>0.0.1 Class creation.</li>
50   * <li>0.0.2 Calls the interface controller with the System implementation.</li>
51   * <li>0.0.3 Specific interface controller.</li>
52   * <li>0.0.4 Logger.</li>
53   * <li>0.0.5 Prompt from the configurator.</li>
54   * <li>0.0.6 Delete the syntax call.</li>
55   * <li>0.1.0 Changed for tests.</li>
56   * <li>0.1.1 Log time.</li>
57   * <li>0.1.2 final.</li>
58   * <li>1.0.0 Moved to version 1.</li>
59   * <li>1.1.0 Types for ui implementations (default).</li>
60   * <li>1.2.0 Prompt property.</li>
61   * <li>1.2.1 Strings externalized.</li>
62   * <li>1.2.2 Assert.</li>
63   * <li>1.3.0 Threaded.</li>
64   * <li>1.3.1 Load synchronization.</li>
65   * <li>1.3.2 Synchronization optional.</li>
66   * <li>1.3.3 Show help.</li>
67   * <li>1.3.4 Interface controller type from Configuration.</li>
68   * <li>1.3.5 Attributes with default visibility and throw expetion.</li>
69   * </ul>
70   *
71   * @author Andres Gomez Casanova <a
72   *         href="mailto:a n g o c a at y a h o o dot c o m">(AngocA)</a>
73   * @version 1.3.5 2010-08-08
74   */
75  public final class Main {
76  
77      // Initializes the graph in another thread defined in an anonymous
78      // class.
79      /**
80       * This class is another thread to execute the grammar reader and create the
81       * graph in a parallel way. That helps to show rapidly the prompt to the
82       * user, and in the background all the other components are loaded.
83       * <p>
84       * TODO v1.0 Arreglar este bazar de sincronizacion, no es necesario todo
85       * eso.
86       *
87       * @author Andres Gomez Casanova <a
88       *         href="mailto:a n g o c a at y a h o o dot c o m" >(AngocA)</a>
89       * @version 1.0.0 2010-02-24
90       */
91      class BackgroundGrammarLoader extends Thread {
92          /**
93           * Object that keeps the load state.
94           */
95          private final SynchronizedLoad synchronizeLoad;
96  
97          /**
98           * Constructor that associates an object that permits to synchronize the
99           * threads.
100          *
101          * @param synchronizedLoad
102          *            Status of the thread.
103          */
104         public BackgroundGrammarLoader(
105                 final SynchronizedLoad/* ! */synchronizedLoad) {
106             super("GrammarLoaderThread");
107             this.synchronizeLoad = synchronizedLoad;
108         }
109 
110         /*
111          * (non-Javadoc)
112          * @see java.lang.Thread#run()
113          */
114         @Override
115         public void run() {
116             // Checks if the first thread has finished.
117             if (!this.synchronizeLoad.isAlreadyLoaded()) {
118                 synchronized (this) {
119                     try {
120                         this.wait();
121                     } catch (final InterruptedException exception) {
122                         Main.LOGGER.error(exception.getMessage());
123                         Main.LOGGER.info(exception.getStackTrace().toString());
124                     }
125                 }
126             }
127             // Loads the grammar in background.
128             try {
129                 InterfaceCore.initializeGraph();
130             } catch (final AbstractZemucanException exception) {
131                 Main.LOGGER.error(exception.getMessage());
132                 Main.LOGGER.info(exception.getStackTrace().toString());
133                 exception.printStackTrace();
134                 System.exit(Main.INITIALIZING_ERROR);
135             }
136         }
137     }
138 
139     /**
140      * Default controller.
141      */
142     static final int ID_DEFAULT_CONTROLLER = Main.ID_JLINE;
143     /**
144      * JLine implementation as user interface.
145      */
146     static final int ID_JLINE = 1;
147 
148     /**
149      * System implementation as user interface.
150      */
151     static final int ID_SYSTEM = 0;
152     /**
153      * Error while initializing the grammar.
154      */
155     public static final int INITIALIZING_ERROR = -1;
156     /**
157      * Property of the configuration file to determine the interface controller
158      * type.
159      */
160     private static final String INTERFACE_CONTROLLER_TYPE_PROPERTY = "InterfaceControllerType";
161     /**
162      * Logger.
163      */
164     private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
165     /**
166      * Property: Prompt.
167      */
168     static final String PROMPT_PROPERTY = "Prompt"; //$NON-NLS-1$
169     /**
170      * Prompt for the console.
171      */
172     private static final String PROMPT_VALUE = "DB2>"; //$NON-NLS-1$
173     /**
174      * Property of the configuration file to process the grammar in a separated
175      * thread.
176      */
177     private static final String SEPARATED_THREAD = "SeparatedThreadForGrammar";
178     /**
179      * Value for processing the grammar in a separated process.
180      */
181     private static final Object TRUE = "true";
182     /**
183      * Default controller value.
184      */
185     private static final String VALUE_DEFAULT_CONTROLLER = Main.VALUE_JLINE;
186     /**
187      * JLine implementation as user interface value.
188      */
189     static final String VALUE_JLINE = "jline";
190 
191     /**
192      * System implementation as user interface value.
193      */
194     static final String VALUE_SYSTEM = "system";
195 
196     /**
197      * Parses the parameters and returns the interface controller type.
198      *
199      * @param args
200      *            Arguments.
201      * @return Type of controller.
202      */
203     static int getInterfaceControllerType(final String[]/* [!]! */args) {
204         assert args != null;
205         boolean assertsEnabled = false;
206         // Intentional side-effect!
207         assert assertsEnabled = true;
208         if (assertsEnabled) {
209             for (final String string : args) {
210                 assert string != null;
211             }
212         }
213 
214         int type = Main.ID_DEFAULT_CONTROLLER;
215         if (args.length > 0) {
216             type = Main.processInterfaceControllerType(args[0]);
217         } else {
218             final String prompt = Configurator.getInstance().getProperty(
219                     Main.INTERFACE_CONTROLLER_TYPE_PROPERTY);
220             type = Main.processInterfaceControllerType(prompt);
221         }
222         return type;
223     }
224 
225     /**
226      * Main method.
227      *
228      * @param args
229      *            Arguments for the main method.
230      * @throws AbstractZemucanException
231      *             If there is a problem reading the graph.
232      */
233     public static void main(final String[]/* [!]! */args)
234             throws AbstractZemucanException {
235         Main.LOGGER.debug("Application Start {}", //$NON-NLS-1$
236                 System.currentTimeMillis());
237 
238         new Main(args);
239     }
240 
241     /**
242      * Starts the selected user interface.
243      *
244      * @param type
245      *            Type of user interface.
246      * @return The interface instantiated.
247      * @throws InputReaderException
248      *             If there is a problem establishing the interface controller
249      *             or user interface.
250      */
251     static AbstractInterfaceController/* ! */prepare(final int type)
252             throws InputReaderException {
253         assert (type == Main.ID_JLINE) || (type == Main.ID_SYSTEM);
254 
255         String prompt = Configurator.getInstance().getProperty(
256                 Main.PROMPT_PROPERTY);
257         if (prompt == null) {
258             prompt = Main.PROMPT_VALUE;
259         }
260         AbstractInterfaceController controller = null;
261         if (type == Main.ID_SYSTEM) {
262             controller = new ImplementationSystemInterfaceController(prompt);
263         } else if (type == Main.ID_JLINE) {
264             controller = new ImplementationJlineInterfaceController(prompt);
265         } else {
266             // Error.
267             assert false;
268         }
269 
270         assert controller != null;
271 
272         return controller;
273     }
274 
275     /**
276      * Retrieves the interface controller type from a string.
277      *
278      * @param text
279      *            name of the interface controller.
280      * @return Type of the interface controller. Default is name is
281      *         unrecognized.
282      */
283     private static int processInterfaceControllerType(final String/* ! */text) {
284         assert text != null;
285 
286         int type = Main.ID_DEFAULT_CONTROLLER;
287         if (text.equals(Main.VALUE_SYSTEM)) {
288             type = Main.ID_SYSTEM;
289         } else if (text.equals(Main.VALUE_JLINE)) {
290             type = Main.ID_JLINE;
291         } else {
292             Main.LOGGER.error("Unsupported interface controller type value. "
293                     + "Using default '" + Main.VALUE_DEFAULT_CONTROLLER + "'.");
294         }
295         return type;
296     }
297 
298     /**
299      * Constructor of the main, that creates the threads.
300      *
301      * @param args
302      * @throws AbstractZemucanException
303      */
304     Main(final String[]/* [!]! */args) throws AbstractZemucanException {
305         assert args != null;
306         boolean assertsEnabled = false;
307         // Intentional side-effect!
308         assert assertsEnabled = true;
309         if (assertsEnabled) {
310             for (final String string : args) {
311                 assert string != null;
312             }
313         }
314 
315         // Process other options, different to default behavior.
316         if ((args.length == 1)
317                 && (args[0].equals("-h") || args[0].equals("--help") || args[0]
318                         .equals("/h"))) {
319             this.showHelp();
320         } else {
321             // Loads the prompt.
322             try {
323                 final int interfaceControllerType = Main
324                         .getInterfaceControllerType(args);
325                 final AbstractInterfaceController controller = Main
326                         .prepare(interfaceControllerType);
327 
328                 SynchronizedLoad synchronizedLoad = null;
329                 Main.BackgroundGrammarLoader thread = null;
330                 // Analyzes the grammar in a separated thread depending on the
331                 // configuration file.
332                 final String separatedThread = Configurator.getInstance()
333                         .getProperty(Main.SEPARATED_THREAD);
334                 if ((separatedThread != null)
335                         && separatedThread.equals(Main.TRUE)) {
336                     synchronizedLoad = new SynchronizedLoad();
337                     thread = new BackgroundGrammarLoader(synchronizedLoad);
338                     thread.setPriority(Thread.MIN_PRIORITY);
339                     thread.start();
340                 }
341                 controller.start(thread, synchronizedLoad);
342             } catch (final AbstractZemucanException exception) {
343                 Main.LOGGER.error(exception.getMessage());
344                 Main.LOGGER.info(exception.getStackTrace().toString());
345                 throw exception;
346             }
347         }
348     }
349 
350     /**
351      * Shows a help message.
352      */
353     private void showHelp() {
354         final String help = "Call the application with one of those flags: '"
355                 + Main.VALUE_JLINE + "', '" + Main.VALUE_SYSTEM
356                 + "'. If you don't select a flag, the default will be '"
357                 + Main.VALUE_DEFAULT_CONTROLLER + "'.\nFor example:\n"
358                 + "sa.sh jline (For linux)\nsa.bat jline (For Windows)";
359         Main.LOGGER.error(help);
360     }
361 }