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    }