View Javadoc

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 }