source: trunk/gli/src/org/greenstone/gatherer/shell/GShell.java@ 5785

Last change on this file since 5785 was 5785, checked in by mdewsnip, 21 years ago

Commented out about 60 unused functions.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.shell;
38
39import java.io.*;
40import javax.swing.*;
41import javax.swing.event.*;
42import javax.swing.tree.*;
43import org.greenstone.gatherer.Dictionary;
44import org.greenstone.gatherer.Gatherer;
45import org.greenstone.gatherer.msm.GreenstoneArchiveParser;
46import org.greenstone.gatherer.shell.GShellListener;
47import org.greenstone.gatherer.shell.GShellProgressMonitor;
48
49/** The <strong>GShell</strong> is reponsible for running a separately threaded process in the command shell. This is necessary for executing the Perl Scripts and also for other system related funcitonality.
50 */
51public class GShell
52 extends Thread {
53 /** A flag used to determine if this process has been asked to cancel. */
54 private boolean cancel = false;
55 /** The list of listeners associated with this class. */
56 private EventListenerList listeners = null;
57 /** The current status of this shell process. */
58 private int status = -1;
59 /** The type of message being sent. */
60 private int msg_type = -1;
61 /** The type of shell process. */
62 private int type = -1;
63 /** The caller of this process, and thus the class most interested in messages. */
64 private GShellListener caller = null;
65 /** The progress monitor associated with this process. */
66 private GShellProgressMonitor progress = null;
67 /** Arguments to be given to the process (including the executable you are calling. */
68 private String args[] = null;
69 /** Element in process type enumeration. */
70 static final public int BUILD = 0;
71 /** Element in process type enumeration. */
72 static final public int IMPORT = 1;
73 /** Element in process type enumeration. */
74 static final public int NEW = 2;
75 /** Element in process type enumeration. */
76 static final public int OTHER = 3;
77 /** Element in status type enumeration. */
78 static final public int ERROR = 0;
79 /** Element in status type enumeration. */
80 static final public int OK = 1;
81 /** Element in process type name enumeration. */
82 static public String GSHELL_BUILD = "gshell_build";
83 /** Element in process type name enumeration. */
84 static public String GSHELL_IMPORT = "gshell_import";
85 /** Element in process type name enumeration. */
86 static public String GSHELL_NEW = "gshell_new";
87 /** Constructor gatherer all the data required to create a new process, and emit meaningfull messages.
88 * @param args A <strong>String[]</strong> containing the arguments to the process thread, including the name of the executable.
89 * @param type An <strong>int</strong> that indicates what group of processes this process belongs to, as some are treated slightly differently (i.e an IMPORT type process is always followed by a BUILD one).
90 * @param msg_type As process threads may be background (like a makecol.pl call) or important processes in their own right (such as an IMPORT-BUILD) we must be able to set what level messages posted by this class will have by usings this <strong>int</strong>.
91 * @param caller The default <i>GShellListener</i> that is interested in the progress of this process.
92 * @param progress The <i>GShellProgressMonitor</i> associated with this process.
93 * @param name A <strong>String</strong> identifier given to the process, for convience and debug reasons.
94 */
95 public GShell(String args[], int type, int msg_type, GShellListener caller, GShellProgressMonitor progress, String name) {
96 super(name);
97 this.args = args;
98 this.msg_type = msg_type;
99 this.type = type;
100 this.caller = caller;
101 this.progress = progress;
102 this.status = 0;
103 // Lower this jobs priority
104 this.setPriority(Thread.MIN_PRIORITY);
105 listeners = new EventListenerList();
106 listeners.add(GShellListener.class, caller);
107 }
108 /** This method adds another shell listener to this process.
109 * @param listener The new <i>GShellListener</i>.
110 */
111 public void addGShellListener(GShellListener listener) {
112 listeners.add(GShellListener.class, listener);
113 }
114 /** This method removes a certain shell listener from this process.
115 * @param listener The <i>GShellListener</i> to be removed.
116 */
117 /* private void removeGShellListener(GShellListener listener) {
118 listeners.remove(GShellListener.class, listener);
119 } */
120 /** Any threaded class must include this method to allow the thread body to be run. */
121 public void run() {
122 if(progress != null) {
123 progress.start();
124 }
125 // Determine if the user has asked for an outfile.
126 String out_name = null;
127 BufferedOutputStream bos = null;
128 if(type == IMPORT || type == BUILD) {
129 if(type == IMPORT) {
130 out_name = (String) Gatherer.c_man.getCollection().build_options.getImportValue("out");
131 }
132 else {
133 out_name = (String) Gatherer.c_man.getCollection().build_options.getBuildValue("out");
134 }
135 if(out_name != null && out_name.length() > 0) {
136 try {
137 bos = new BufferedOutputStream(new FileOutputStream(new File(out_name), true));
138 }
139 catch (Exception error) {
140 Gatherer.printStackTrace(error);
141 }
142 }
143 }
144 // Issue a processBegun event
145 fireProcessBegun(type, status);
146 try {
147
148 String command = "";
149 for(int i = 0; i < args.length; i++) {
150 command = command + args[i] + " ";
151 }
152 ///ystem.err.println("Command: " + command);
153 fireMessage(type, Dictionary.get("GShell.Command") + ": " + command, status);
154
155 Runtime rt = Runtime.getRuntime();
156 Process prcs = rt.exec(args);
157 InputStreamReader eisr = new InputStreamReader( prcs.getErrorStream() );
158 InputStreamReader stdinisr = new InputStreamReader( prcs.getInputStream() );
159 BufferedReader ebr = new BufferedReader( eisr );
160 BufferedReader stdinbr = new BufferedReader( stdinisr );
161 // Captures the std err of a program and pipes it into std in of java
162 String eline = null;
163 String stdinline = null;
164 while (((eline = ebr.readLine()) != null || (stdinline = stdinbr.readLine()) != null) && !hasSignalledStop()) {
165 if(eline != null) {
166 if(progress != null) {
167 progress.parse(eline);
168 }
169 if(bos != null) {
170 try {
171 bos.write(eline.getBytes(), 0, eline.length());
172 }
173 catch(Exception error) {
174 Gatherer.printStackTrace(error);
175 }
176 }
177 fireMessage(type, typeAsString(type) + "> " + eline, status);
178 }
179 if(stdinline != null) {
180 fireMessage(type, typeAsString(type) + "> " + stdinline, status);
181 }
182 }
183
184 if(!hasSignalledStop()) {
185 // Now display final message based on exit value
186 prcs.waitFor();
187
188 if(prcs.exitValue() == 0) {
189 status = OK;
190 fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Success"), status);
191 }
192 else {
193 status = ERROR;
194 fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Failure"), status);
195 }
196 }
197 else {
198 // I need to somehow kill the child process. Unfortunately Thread.stop() and Process.destroy() both fail to do this. But now, thankx to the magic of Michaels 'close the stream suggestion', it works fine (no it doesn't!)
199 prcs.getInputStream().close();
200 prcs.getOutputStream().close();
201 prcs.destroy();
202 status = ERROR;
203 }
204 }
205 // Exception
206 catch (Exception error) {
207 Gatherer.printStackTrace(error);
208 status = ERROR;
209 }
210 // If no error occured, and this was an import process we now extract any new metadata from the archive directory.
211 if(status == OK && type == IMPORT) {
212 fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Parsing_Metadata_Start"), status);
213 new GreenstoneArchiveParser(progress, this);
214 fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Parsing_Metadata_Complete"), status);
215 }
216 // Tidy up.
217 if(progress != null) {
218 progress.stop();
219 }
220 // We're done.
221 fireProcessComplete(type, status);
222 // Close bos
223 if(bos != null) {
224 try {
225 bos.close();
226 bos = null;
227 }
228 catch(Exception error) {
229 Gatherer.printStackTrace(error);
230 }
231 }
232 }
233 /** Method for firing a message to all interested listeners.
234 * @param type An <strong>int</strong> indicating the process type.
235 * @param message The message as a <strong>String</strong>.
236 * @param status An <strong>int</strong> specifying the current status of the process.
237 */
238 public void fireMessage(int type, String message, int status) {
239 GShellEvent event = new GShellEvent(this, 0, type, message, status);
240 Object[] concerned = listeners.getListenerList();
241 for(int i = 0; i < concerned.length ; i++) {
242 if(concerned[i] == GShellListener.class) {
243 ((GShellListener)concerned[i+1]).message(event);
244 }
245 }
246 }
247
248 /** Method for firing a process begun event which is called, strangly enough, when the process begins.
249 * @param type An <strong>int</strong> indicating the process type.
250 * @param status An <strong>int</strong> specifying the current status of the process.
251 */
252 protected void fireProcessBegun(int type, int status) {
253 GShellEvent event = new GShellEvent(this, 0, type, "", status);
254 Object[] concerned = listeners.getListenerList();
255 for(int i = 0; i < concerned.length ; i++) {
256 if(concerned[i] == GShellListener.class) {
257 ((GShellListener)concerned[i+1]).processBegun(event);
258 }
259 }
260 }
261 /** Method for firing a process complete event which is called, no surprise here, when the process ends.
262 * @param type An <strong>int</strong> indicating the process type.
263 * @param status An <strong>int</strong> specifying the current status of the process.
264 */
265 protected void fireProcessComplete(int type, int status) {
266 GShellEvent event = new GShellEvent(this, 0, type, "", status);
267 Object[] concerned = listeners.getListenerList();
268 for(int i = 0; i < concerned.length ; i++) {
269 if(concerned[i] == GShellListener.class) {
270 ((GShellListener)concerned[i+1]).processComplete(event);
271 }
272 }
273 }
274
275 /** Method to determine if the user, via the progress monitor, has signalled stop.
276 * @return A <strong>boolean</strong> indicating if the user wanted to stop.
277 */
278 private boolean hasSignalledStop() {
279 boolean has_signalled_stop = false;
280 if(progress != null) {
281 return progress.hasSignalledStop();
282 }
283 return has_signalled_stop;
284 }
285
286 /** Converts a type into a text representation.
287 * @param type An <strong>int</strong> which maps to a shell process type.
288 * @return A <strong>String</strong> which is the thread process's text name.
289 */
290 public String typeAsString(int type) {
291 String name = null;
292 switch(type) {
293 case BUILD:
294 name = Dictionary.get("GShell.Build");
295 break;
296 case IMPORT:
297 name = Dictionary.get("GShell.Import");
298 break;
299 case NEW:
300 name = Dictionary.get("GShell.New");
301 break;
302 default:
303 name = Dictionary.get("GShell.Other");
304 }
305 return name;
306 }
307}
Note: See TracBrowser for help on using the repository browser.