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 }