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 package org.apache.commons.daemon.support; 019 020 import org.apache.commons.daemon.DaemonContext; 021 import org.apache.commons.daemon.DaemonController; 022 023 import java.lang.reflect.Method; 024 025 /* 026 * Used by jsvc for Daemon management. 027 * 028 * @version 1.0 <i>(SVN $Revision: 925053 $)</i> 029 */ 030 public final class DaemonLoader 031 { 032 033 // N.B. These static mutable variables need to be accessed using synch. 034 private static Controller controller = null; //@GuardedBy("this") 035 private static Object daemon = null; //@GuardedBy("this") 036 /* Methods to call */ 037 private static Method init = null; //@GuardedBy("this") 038 private static Method start = null; //@GuardedBy("this") 039 private static Method stop = null; //@GuardedBy("this") 040 private static Method destroy = null; //@GuardedBy("this") 041 042 public static void version() 043 { 044 System.err.println("java version \"" + 045 System.getProperty("java.version") + "\""); 046 System.err.println(System.getProperty("java.runtime.name") + 047 " (build " + 048 System.getProperty("java.runtime.version") + ")"); 049 System.err.println(System.getProperty("java.vm.name") + 050 " (build " + 051 System.getProperty("java.vm.version") + 052 ", " + System.getProperty("java.vm.info") + ")"); 053 } 054 055 public static boolean check(String cn) 056 { 057 try { 058 /* Check the class name */ 059 if (cn == null) 060 throw new NullPointerException("Null class name specified"); 061 062 /* Get the ClassLoader loading this class */ 063 ClassLoader cl = DaemonLoader.class.getClassLoader(); 064 if (cl == null) { 065 System.err.println("Cannot retrieve ClassLoader instance"); 066 return false; 067 } 068 069 /* Find the required class */ 070 Class c = cl.loadClass(cn); 071 072 /* This should _never_ happen, but doublechecking doesn't harm */ 073 if (c == null) 074 throw new ClassNotFoundException(cn); 075 076 /* Create a new instance of the daemon */ 077 c.newInstance(); 078 079 } catch (Throwable t) { 080 /* In case we encounter ANY error, we dump the stack trace and 081 * return false (load, start and stop won't be called). 082 */ 083 t.printStackTrace(System.err); 084 return false; 085 } 086 /* The class was loaded and instantiated correctly, we can return 087 */ 088 return true; 089 } 090 091 public static boolean load(String cn, String ar[]) 092 { 093 try { 094 /* Make sure any previous instance is garbage collected */ 095 System.gc(); 096 097 /* Check if the underlying libray supplied a valid list of 098 arguments */ 099 if (ar == null) 100 ar = new String[0]; 101 102 /* Check the class name */ 103 if (cn == null) 104 throw new NullPointerException("Null class name specified"); 105 106 /* Get the ClassLoader loading this class */ 107 ClassLoader cl = DaemonLoader.class.getClassLoader(); 108 if (cl == null) { 109 System.err.println("Cannot retrieve ClassLoader instance"); 110 return false; 111 } 112 113 /* Find the required class */ 114 Class c = cl.loadClass(cn); 115 116 /* This should _never_ happen, but doublechecking doesn't harm */ 117 if (c == null) 118 throw new ClassNotFoundException(cn); 119 120 /* Check interface */ 121 boolean isdaemon = false; 122 try { 123 Class dclass = 124 cl.loadClass("org.apache.commons.daemon.Daemon"); 125 isdaemon = dclass.isAssignableFrom(c); 126 } catch (Exception cnfex) { 127 // Swallow if Daemon not found. 128 } 129 130 /* Check methods */ 131 Class[]myclass = new Class[1]; 132 if (isdaemon) { 133 myclass[0] = DaemonContext.class; 134 } 135 else { 136 myclass[0] = ar.getClass(); 137 } 138 139 init = c.getMethod("init", myclass); 140 141 myclass = null; 142 start = c.getMethod("start", myclass); 143 stop = c.getMethod("stop", myclass); 144 destroy = c.getMethod("destroy", myclass); 145 146 /* Create a new instance of the daemon */ 147 daemon = c.newInstance(); 148 149 if (isdaemon) { 150 /* Create a new controller instance */ 151 controller = new Controller(); 152 153 /* Set the availability flag in the controller */ 154 controller.setAvailable(false); 155 156 /* Create context */ 157 Context context = new Context(); 158 context.setArguments(ar); 159 context.setController(controller); 160 161 /* Now we want to call the init method in the class */ 162 Object arg[] = new Object[1]; 163 arg[0] = context; 164 init.invoke(daemon, arg); 165 } 166 else { 167 Object arg[] = new Object[1]; 168 arg[0] = ar; 169 init.invoke(daemon, arg); 170 } 171 172 } catch (Throwable t) { 173 /* In case we encounter ANY error, we dump the stack trace and 174 * return false (load, start and stop won't be called). 175 */ 176 t.printStackTrace(System.err); 177 return false; 178 } 179 /* The class was loaded and instantiated correctly, we can return */ 180 return true; 181 } 182 183 public static boolean start() 184 { 185 try { 186 /* Attempt to start the daemon */ 187 Object arg[] = null; 188 start.invoke(daemon, arg); 189 190 /* Set the availability flag in the controller */ 191 if (controller != null) 192 controller.setAvailable(true); 193 194 } catch (Throwable t) { 195 /* In case we encounter ANY error, we dump the stack trace and 196 * return false (load, start and stop won't be called). 197 */ 198 t.printStackTrace(System.err); 199 return false; 200 } 201 return true; 202 } 203 204 public static boolean stop() 205 { 206 try { 207 /* Set the availability flag in the controller */ 208 if (controller != null) 209 controller.setAvailable(false); 210 211 /* Attempt to stop the daemon */ 212 Object arg[] = null; 213 stop.invoke(daemon, arg); 214 215 /* Run garbage collector */ 216 System.gc(); 217 218 } 219 catch (Throwable t) { 220 /* In case we encounter ANY error, we dump the stack trace and 221 * return false (load, start and stop won't be called). 222 */ 223 t.printStackTrace(System.err); 224 return false; 225 } 226 return true; 227 } 228 229 public static boolean destroy() 230 { 231 try { 232 /* Attempt to stop the daemon */ 233 Object arg[] = null; 234 destroy.invoke(daemon, arg); 235 236 /* Run garbage collector */ 237 daemon = null; 238 controller = null; 239 System.gc(); 240 241 } catch (Throwable t) { 242 /* In case we encounter ANY error, we dump the stack trace and 243 * return false (load, start and stop won't be called). 244 */ 245 t.printStackTrace(System.err); 246 return false; 247 } 248 return true; 249 } 250 251 private static native void shutdown(boolean reload); 252 private static native void failed(String message); 253 254 public static class Controller 255 implements DaemonController 256 { 257 258 private boolean available = false; 259 260 private Controller() 261 { 262 super(); 263 this.setAvailable(false); 264 } 265 266 private boolean isAvailable() 267 { 268 synchronized (this) { 269 return this.available; 270 } 271 } 272 273 private void setAvailable(boolean available) 274 { 275 synchronized (this) { 276 this.available = available; 277 } 278 } 279 280 public void shutdown() 281 throws IllegalStateException 282 { 283 synchronized (this) { 284 if (!this.isAvailable()) { 285 throw new IllegalStateException(); 286 } 287 else { 288 this.setAvailable(false); 289 DaemonLoader.shutdown(false); 290 } 291 } 292 } 293 294 public void reload() 295 throws IllegalStateException 296 { 297 synchronized (this) { 298 if (!this.isAvailable()) { 299 throw new IllegalStateException(); 300 } 301 else { 302 this.setAvailable(false); 303 DaemonLoader.shutdown(true); 304 } 305 } 306 } 307 308 public void fail() 309 throws IllegalStateException 310 { 311 fail(null, null); 312 } 313 314 public void fail(String message) 315 throws IllegalStateException 316 { 317 fail(message, null); 318 } 319 320 public void fail(Exception exception) 321 throws IllegalStateException 322 { 323 fail(null, exception); 324 } 325 326 public void fail(String message, Exception exception) 327 throws IllegalStateException 328 { 329 synchronized (this) { 330 if (!this.isAvailable()) { 331 throw new IllegalStateException(); 332 } 333 else { 334 this.setAvailable(false); 335 String msg = message; 336 if (exception != null) { 337 if (msg != null) 338 msg = msg + ": " + exception.toString(); 339 else 340 msg = exception.toString(); 341 } 342 DaemonLoader.failed(msg); 343 } 344 } 345 } 346 347 } 348 349 public static class Context 350 implements DaemonContext 351 { 352 353 private DaemonController daemonController = null; 354 355 private String[] args = null; 356 357 public DaemonController getController() 358 { 359 return daemonController; 360 } 361 362 public void setController(DaemonController controller) 363 { 364 this.daemonController = controller; 365 } 366 367 public String[] getArguments() 368 { 369 return args; 370 } 371 372 public void setArguments(String[]args) 373 { 374 this.args = args; 375 } 376 377 } 378 } 379