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