1 /*
2 * db2sa: DB2 Syntax Assistant
3 * Copyright (C) Andres Gomez Casanova
4 *
5 * This file is part of db2sa.
6 *
7 * db2sa 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 * db2sa 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: 2009-07-08 19:56:43 +0200 (Wed, 08 Jul 2009) $:
26 * Revision: $LastChangedRevision: 357 $:
27 * URL: $HeadURL: https://db2sa.svn.sourceforge.net/svnroot/db2sa/branches/db2sa_beta/source-code/src/main/java/name/angoca/db2sa/core/executer/Executer.java $:
28 */
29 package name.angoca.db2sa.core.executer;
30
31 import java.io.BufferedReader;
32 import java.io.IOException;
33 import java.io.InputStreamReader;
34 import java.io.Reader;
35 import java.util.StringTokenizer;
36
37 import name.angoca.db2sa.Configurator;
38 import name.angoca.db2sa.Constants;
39 import name.angoca.db2sa.ExecutionState;
40 import name.angoca.db2sa.cli.OutputWriter;
41 import name.angoca.db2sa.cli.exceptions.OutputWriterException;
42 import name.angoca.db2sa.messages.Messages;
43
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48 * This is the implementation of the executer. TODO validar que la ejecución de
49 * DB2 se puede hacer desde una misma clase en varias plataformas, o si es
50 * necesario validar esto. <br/>
51 * <b>Control Version</b><br />
52 * <ul>
53 * <li>0.0.1 Class creation.</li>
54 * <li>0.1.0 Singleton pattern, analyze of exit token.</li>
55 * <li>0.1.1 Use of streams.</li>
56 * <li>0.1.2 Execution state.</li>
57 * <li>0.1.3 Enum.</li>
58 * <li>0.1.4 Close de streams and get instance synchronized.</li>
59 * <li>0.1.5 Name of a state.</li>
60 * <li>0.1.6 final.</li>
61 * <li>1.0.0 Moved to version 1.</li>
62 * </ul>
63 *
64 * @author Andres Gomez Casanova <a
65 * href="mailto:a n g o c a at y a h o o dot c o m">(AngocA)</a>
66 * @version 1.0.0 2009-07-19
67 */
68 public final class Executer {
69 /**
70 * Logger.
71 */
72 private static final Logger LOGGER = LoggerFactory
73 .getLogger(Executer.class);
74
75 /**
76 * Singleton pattern.
77 */
78 private static Executer s_instance;
79
80 /**
81 * Set of tokens to exit the execution.
82 */
83 private final String m_tokens;
84
85 /**
86 * Private default constructor.
87 */
88 private Executer() {
89 this.m_tokens = Configurator.getInstance().getProperty(Constants.EXIT);
90 if (this.m_tokens == null) {
91 // TODO Lanzar una excepción propia
92 throw new RuntimeException(Messages
93 .getString("JlineInterfaceController" //$NON-NLS-1$
94 + ".NoExitTokensDefined")); //$NON-NLS-1$
95 }
96 }
97
98 /**
99 * Implementation of Singleton pattern, returns the sole instance.
100 *
101 * @return The sole instance of the executer.
102 */
103 public static Executer getInstance() {
104 synchronized (Executer.LOGGER) {
105 if (Executer.s_instance == null) {
106 Executer.s_instance = new Executer();
107 }
108 }
109 return Executer.s_instance;
110 }
111
112 /**
113 * Executes the given command and returns a code that means the execution
114 * state.
115 *
116 * @param command
117 * Command to execute.
118 * @param writer
119 * The output's writer.
120 * @return A signal that indicates the state of the command.
121 * @throws OutputWriterException
122 * If there is a problem when writing.
123 */
124 public ExecutionState/* ! */execute(final String/* ! */command,
125 final OutputWriter/* ! */writer) throws OutputWriterException {
126 // No body uses the unknown state, it just for initialize the variable.
127 ExecutionState state = ExecutionState.UNKNOWN;
128
129 BufferedReader bfStream = null;
130 Reader reader = null;
131
132 try {
133 // TODO la salida estandar y de error cómo se van a manejar?
134 // TODO Cuando el comando no empieza con la palabra DB2 y no es
135 // ninguno de los otros comandos, adicionar este palabra y
136 // ejecutarlo sobre DB2
137 Executer.LOGGER.info("Execute: {}", command); //$NON-NLS-1$
138
139 if (this.isAnExitToken(command)) {
140 state = ExecutionState.APPLICATION_EXIT;
141 } else {
142 state = ExecutionState.EXECUTED;
143 if (command.compareTo("") != 0) { //$NON-NLS-1$
144 // TODO Analizar los comandos que no comienzan con la parte
145 // de db2.
146 // TODO usar el output printer para no tener que concatenar
147 // la salida
148 // TODO usar un input stream para poder modificar el comando
149 // ejecutado (como cuando se pide la contrasegna)
150 // TODO finalizar o cerrar todos los objetos despues de
151 // usados
152 final Process proc = Runtime.getRuntime().exec(command);
153 reader = new InputStreamReader(proc.getInputStream());
154 bfStream = new BufferedReader(reader);
155 String current = ""; //$NON-NLS-1$
156 while (current != null) {
157 current = bfStream.readLine();
158 if (current != null) {
159 writer.writeLine(current);
160 }
161 }
162 }
163 }
164 } catch (IOException e) {
165 // TODO Auto-generated catch block
166 e.printStackTrace();
167 } finally {
168
169 try {
170 if (bfStream != null) {
171 bfStream.close();
172 }
173 } catch (IOException e) {
174 // TODO Auto-generated catch block
175 e.printStackTrace();
176 }
177
178 try {
179 if (reader != null) {
180 reader.close();
181 }
182 } catch (IOException e) {
183 // TODO Auto-generated catch block
184 e.printStackTrace();
185 }
186 }
187 Executer.LOGGER.debug("{} -> {}", command, state); //$NON-NLS-1$
188 return state;
189 }
190
191 /**
192 * @param command
193 * @return
194 */
195 /**
196 * Analyze the current command to see if the application has to finish.
197 *
198 * @param command
199 * Command entered.
200 * @return true if the application has to finish.
201 */
202 private boolean isAnExitToken(final String/* ! */command) {
203 boolean exit = false;
204 final StringTokenizer tokens = new StringTokenizer(this.m_tokens);
205 while (tokens.hasMoreElements()) {
206 // FIXME cuando se hace ctrl + D hay una excepcion aqui.
207 if (command.compareToIgnoreCase(tokens.nextToken()) == 0) {
208 exit = true;
209 }
210 }
211 return exit;
212 }
213 }