001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 /* @version $Id: DaemonLoader.java 912665 2010-02-22 17:16:00Z sebb $ */
019
020 package org.apache.commons.daemon.support;
021
022 import org.apache.commons.daemon.DaemonContext;
023 import org.apache.commons.daemon.DaemonController;
024
025 import java.lang.reflect.Method;
026
027 public final class DaemonLoader {
028
029 private static Controller controller = null;
030 private static Context context = null;
031 private static Object daemon = null;
032 /* Methods to call */
033 private static Method init = null;
034 private static Method start = null;
035 private static Method stop = null;
036 private static Method destroy = null;
037
038 public static void version() {
039 System.err.println("java version \""+
040 System.getProperty("java.version")+
041 "\"");
042 System.err.println(System.getProperty("java.runtime.name")+
043 " (build "+
044 System.getProperty("java.runtime.version")+
045 ")");
046 System.err.println(System.getProperty("java.vm.name")+
047 " (build "+
048 System.getProperty("java.vm.version")+
049 ", "+
050 System.getProperty("java.vm.info")+
051 ")");
052 }
053
054 public static boolean check(String cn) {
055 try {
056 /* Check the class name */
057 if (cn==null)
058 throw new NullPointerException("Null class name specified");
059
060 /* Get the ClassLoader loading this class */
061 ClassLoader cl=DaemonLoader.class.getClassLoader();
062 if (cl==null) {
063 System.err.println("Cannot retrieve ClassLoader instance");
064 return(false);
065 }
066
067 /* Find the required class */
068 Class c=cl.loadClass(cn);
069
070 /* This should _never_ happen, but doublechecking doesn't harm */
071 if (c==null) throw new ClassNotFoundException(cn);
072
073 /* Create a new instance of the daemon */
074 Object s=c.newInstance();
075
076 } catch (Throwable t) {
077 /* In case we encounter ANY error, we dump the stack trace and
078 return false (load, start and stop won't be called). */
079 t.printStackTrace(System.err);
080 return(false);
081 }
082 /* The class was loaded and instantiated correctly, we can return */
083 return(true);
084 }
085
086 public static boolean load(String cn, String ar[]) {
087 try {
088 /* Make sure any previous instance is garbage collected */
089 System.gc();
090
091 /* Check if the underlying libray supplied a valid list of
092 arguments */
093 if (ar==null) ar=new String[0];
094
095 /* Check the class name */
096 if (cn==null)
097 throw new NullPointerException("Null class name specified");
098
099 /* Get the ClassLoader loading this class */
100 ClassLoader cl=DaemonLoader.class.getClassLoader();
101 if (cl==null) {
102 System.err.println("Cannot retrieve ClassLoader instance");
103 return(false);
104 }
105
106 /* Find the required class */
107 Class c=cl.loadClass(cn);
108
109 /* This should _never_ happen, but doublechecking doesn't harm */
110 if (c==null) throw new ClassNotFoundException(cn);
111
112 /* Check interface */
113 boolean isdaemon = false;
114 try {
115 Class dclass = cl.loadClass("org.apache.commons.daemon.Daemon");
116 isdaemon = dclass.isAssignableFrom(c);
117 } catch(Exception cnfex) {
118 // Swallow if Daemon not found.
119 }
120
121 /* Check methods */
122 Class[] myclass = new Class[1];
123 if (isdaemon) {
124 myclass[0] = DaemonContext.class;
125 } else {
126 myclass[0] = ar.getClass();
127 }
128
129 init = c.getMethod("init",myclass);
130
131 myclass = null;
132 start = c.getMethod("start",myclass);
133
134 stop = c.getMethod("stop",myclass);
135
136 destroy = c.getMethod("destroy",myclass);
137
138 /* Create a new instance of the daemon */
139 daemon=c.newInstance();
140
141 if (isdaemon) {
142 /* Create a new controller instance */
143 controller=new Controller();
144
145 /* Set the availability flag in the controller */
146 controller.setAvailable(false);
147
148 /* Create context */
149 context = new Context();
150 context.setArguments(ar);
151 context.setController(controller);
152
153 /* Now we want to call the init method in the class */
154 Object arg[] = new Object[1];
155 arg[0] = context;
156 init.invoke(daemon,arg);
157 } else {
158 Object arg[] = new Object[1];
159 arg[0] = ar;
160 init.invoke(daemon,arg);
161 }
162
163 } catch (Throwable t) {
164 /* In case we encounter ANY error, we dump the stack trace and
165 return false (load, start and stop won't be called). */
166 t.printStackTrace(System.err);
167 return(false);
168 }
169 /* The class was loaded and instantiated correctly, we can return */
170 return(true);
171 }
172
173 public static boolean start() {
174 try {
175 /* Attempt to start the daemon */
176 Object arg[] = null;
177 start.invoke(daemon,arg);
178
179 /* Set the availability flag in the controller */
180 if (controller != null)
181 controller.setAvailable(true);
182
183 } catch (Throwable t) {
184 /* In case we encounter ANY error, we dump the stack trace and
185 return false (load, start and stop won't be called). */
186 t.printStackTrace(System.err);
187 return(false);
188 }
189 return(true);
190 }
191
192 public static boolean stop() {
193 try {
194 /* Set the availability flag in the controller */
195 if (controller != null)
196 controller.setAvailable(false);
197
198 /* Attempt to stop the daemon */
199 Object arg[] = null;
200 stop.invoke(daemon,arg);
201
202 /* Run garbage collector */
203 System.gc();
204
205 } catch (Throwable t) {
206 /* In case we encounter ANY error, we dump the stack trace and
207 return false (load, start and stop won't be called). */
208 t.printStackTrace(System.err);
209 return(false);
210 }
211 return(true);
212 }
213
214 public static boolean destroy() {
215 try {
216 /* Attempt to stop the daemon */
217 Object arg[] = null;
218 destroy.invoke(daemon,arg);
219
220 /* Run garbage collector */
221 daemon=null;
222 controller=null;
223 System.gc();
224
225 } catch (Throwable t) {
226 /* In case we encounter ANY error, we dump the stack trace and
227 return false (load, start and stop won't be called). */
228 t.printStackTrace(System.err);
229 return(false);
230 }
231 return(true);
232 }
233
234 private static native void shutdown(boolean reload);
235
236 public static class Controller implements DaemonController {
237
238 boolean available=false;
239
240 private Controller() {
241 super();
242 this.setAvailable(false);
243 }
244
245 private boolean isAvailable() {
246 synchronized (this) {
247 return(this.available);
248 }
249 }
250
251 private void setAvailable(boolean available) {
252 synchronized (this) {
253 this.available=available;
254 }
255 }
256
257 public void shutdown() throws IllegalStateException {
258 synchronized (this) {
259 if (!this.isAvailable()) {
260 throw new IllegalStateException();
261 } else {
262 this.setAvailable(false);
263 DaemonLoader.shutdown(false);
264 }
265 }
266 }
267
268 public void reload() throws IllegalStateException {
269 synchronized (this) {
270 if (!this.isAvailable()) {
271 throw new IllegalStateException();
272 } else {
273 this.setAvailable(false);
274 DaemonLoader.shutdown(true);
275 }
276 }
277 }
278
279 public void fail()
280 throws IllegalStateException {
281 }
282
283 public void fail(String message)
284 throws IllegalStateException {
285 }
286
287 public void fail(Exception exception)
288 throws IllegalStateException {
289 }
290
291 public void fail(String message, Exception exception)
292 throws IllegalStateException {
293 }
294
295 }
296
297 public static class Context implements DaemonContext {
298
299 DaemonController controller = null;
300
301 String[] args = null;
302
303 public DaemonController getController() {
304 return controller;
305 }
306
307 public void setController(DaemonController controller) {
308 this.controller = controller;
309 }
310
311 public String[] getArguments() {
312 return args;
313 }
314
315 public void setArguments(String[] args) {
316 this.args = args;
317 }
318
319 }
320
321 }