KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > varia > process > ChildProcessService


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software 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 GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.varia.process;
23
24 import java.util.Properties JavaDoc;
25 import java.util.Iterator JavaDoc;
26
27 import java.io.File JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.Reader JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.io.InputStreamReader JavaDoc;
32 import java.io.BufferedReader JavaDoc;
33
34 import org.apache.log4j.Level;
35 import org.apache.log4j.Logger;
36
37 import org.jboss.system.ServiceMBeanSupport;
38
39 import org.jboss.util.NullArgumentException;
40
41 /**
42  * A service to manage a child process.
43  *
44  * @jmx:mbean extends="org.jboss.system.ServiceMBean"
45  *
46  * @version <tt>$Revision: 37459 $</tt>
47  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
48  */

49 public class ChildProcessService
50    extends ServiceMBeanSupport
51    implements ChildProcessServiceMBean
52 {
53    /** The command line of the process to execute. */
54    protected String JavaDoc commandLine;
55
56    /** The environment for the process. */
57    protected Properties JavaDoc env;
58
59    /** The working directory of the process. */
60    protected File JavaDoc workingDir;
61
62    /** The child, we are so proud. */
63    protected Process JavaDoc childProcess;
64
65    /**
66     * The name of the logger adapter for the child process' streams.
67     */

68    protected String JavaDoc loggerAdapterName = this.getClass().getName();
69    
70    /**
71     * The input adapter, which takes the process' STDOUT and
72     * turns them into logger calls.
73     */

74    protected ReaderLoggerAdapter inputAdapter;
75
76    /**
77     * The input adapter, which takes the process' STDERR and
78     * turns them into logger calls.
79     */

80    protected ReaderLoggerAdapter errorAdapter;
81    
82    /**
83     * @jmx:managed-attribute
84     */

85    public void setCommandLine(final String JavaDoc commandLine)
86    {
87       if (commandLine == null)
88          throw new NullArgumentException("commandLine");
89       
90       this.commandLine = commandLine;
91    }
92
93    /**
94     * @jmx:managed-attribute
95     */

96    public String JavaDoc getCommandLine()
97    {
98       return commandLine;
99    }
100
101    /**
102     * @jmx:managed-attribute
103     */

104    public void setEnvironment(final Properties JavaDoc env)
105    {
106       this.env = env;
107    }
108
109    /**
110     * @jmx:managed-attribute
111     */

112    public Properties JavaDoc getEnvironment()
113    {
114       return env;
115    }
116
117    /**
118     * @jmx:managed-attribute
119     */

120    public void setWorkingDirectory(final File JavaDoc dir)
121    {
122       // only check if not null
123
if (dir != null) {
124          if (dir.exists()) {
125             if (!dir.isDirectory()) {
126                throw new IllegalArgumentException JavaDoc
127                   ("Directory argument does not point to a directory: " + dir);
128             }
129          }
130       }
131
132       this.workingDir = dir;
133    }
134
135    /**
136     * @jmx:managed-attribute
137     */

138    public File JavaDoc getWorkingDirectory()
139    {
140       return workingDir;
141    }
142
143    /**
144     * @jmx:managed-attribute
145     */

146    public Integer JavaDoc getExitValue()
147    {
148       if (childProcess != null) {
149          return new Integer JavaDoc(childProcess.exitValue());
150       }
151
152       return null;
153    }
154
155    /**
156     * @jmx:managed-attribute
157     */

158    public void setLoggerAdapterName(final String JavaDoc name)
159    {
160       this.loggerAdapterName = name;
161    }
162
163    /**
164     * @jmx:managed-attribute
165     */

166    public String JavaDoc getLoggerAdapterName()
167    {
168       return loggerAdapterName;
169    }
170    
171    protected String JavaDoc[] makeEnvArray(final Properties JavaDoc props)
172    {
173       if (props == null)
174          return new String JavaDoc[0];
175       
176       String JavaDoc[] envArray = new String JavaDoc[props.keySet().size()];
177
178       Iterator JavaDoc iter = props.keySet().iterator();
179       int i = 0;
180       while (iter.hasNext()) {
181          String JavaDoc name = (String JavaDoc)iter.next();
182          envArray[i++] = name + "=" + props.getProperty(name);
183       }
184
185       return envArray;
186    }
187
188    ///////////////////////////////////////////////////////////////////////////
189
// Reader/InputStream Logger Adapter //
190
///////////////////////////////////////////////////////////////////////////
191

192    protected static class ReaderLoggerAdapter
193       implements Runnable JavaDoc
194    {
195       protected BufferedReader JavaDoc reader;
196       protected boolean shutdown;
197       protected Logger log;
198       protected Level level;
199       
200       public ReaderLoggerAdapter(final Reader JavaDoc reader, final Logger log, final Level level)
201       {
202          if (reader instanceof BufferedReader JavaDoc) {
203             this.reader = (BufferedReader JavaDoc)reader;
204          }
205          else {
206             this.reader = new BufferedReader JavaDoc(reader);
207          }
208
209          this.log = log;
210          this.level = level;
211       }
212
213       public ReaderLoggerAdapter(final InputStream JavaDoc input, final Logger log, final Level level)
214       {
215          this(new InputStreamReader JavaDoc(input), log, level);
216       }
217
218       public void shutdown()
219       {
220          shutdown = true;
221       }
222
223       public void run()
224       {
225          while (!shutdown) {
226             try {
227                String JavaDoc data = reader.readLine();
228                if (data == null) {
229                   try {
230                      Thread.sleep(1000);
231                   }
232                   catch (InterruptedException JavaDoc ignore) {}
233                }
234                else {
235                   log.log(level, data);
236                }
237             }
238             catch (IOException JavaDoc e) {
239                log.error("Failed to read data from reader", e);
240             }
241          }
242       }
243    }
244    
245    
246    ///////////////////////////////////////////////////////////////////////////
247
// ServiceMBeanSupport Overrides //
248
///////////////////////////////////////////////////////////////////////////
249

250    protected void startService() throws Exception JavaDoc
251    {
252       Runtime JavaDoc rt = Runtime.getRuntime();
253
254       childProcess = rt.exec(commandLine, makeEnvArray(env), workingDir);
255       log.info("Spawned child process: " + commandLine);
256
257       // hook up the processes output streams to logging
258
Logger logger = Logger.getLogger(loggerAdapterName);
259       
260       InputStream JavaDoc input = childProcess.getInputStream();
261       inputAdapter = new ReaderLoggerAdapter(input, logger, Level.INFO);
262       new Thread JavaDoc(inputAdapter).start();
263       
264       InputStream JavaDoc error = childProcess.getErrorStream();
265       errorAdapter = new ReaderLoggerAdapter(error, logger, Level.ERROR);
266       new Thread JavaDoc(errorAdapter).start();
267    }
268
269    protected void stopService() throws Exception JavaDoc
270    {
271       childProcess.destroy();
272
273       log.debug("Child process destroyed; waiting for process to exit");
274       childProcess.waitFor();
275
276       log.info("Child exited with code: " + getExitValue());
277
278       inputAdapter.shutdown();
279       errorAdapter.shutdown();
280       
281       childProcess = null;
282       inputAdapter = null;
283       errorAdapter = null;
284    }
285 }
286
Popular Tags