KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > module > Module


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9  */

10 package org.mmbase.module;
11
12 import java.util.*;
13 import java.net.*;
14 import org.xml.sax.*;
15
16 import org.mmbase.util.*;
17 import org.mmbase.util.xml.ModuleReader;
18
19 import org.mmbase.util.functions.*;
20 import org.mmbase.util.logging.Logging;
21 import org.mmbase.util.logging.Logger;
22
23 /**
24  * An MMBase Module is an extension of this class, which is configured by an XML in the <mmbase
25  * config dir >/modules directory. All XML's (which are defined 'active') in this directory are
26  * automaticly loaded, and all found 'Module's are then initialized.
27  *
28  * There are several Modules which are more or less compulsary in MMBase, like the 'mmbaseroot'
29  * module, the actual core of MMBase implemented by {@link org.mmbase.module.core.MMBase}, and the
30  * 'jdbc' module.
31  *
32  * @author Rico Jansen
33  * @author Rob Vermeulen (securitypart)
34  * @author Pierre van Rooden
35  *
36  * @version $Id: Module.java,v 1.77.2.2 2006/09/10 17:04:36 nklasens Exp $
37  */

38 public abstract class Module extends FunctionProvider {
39
40     /**
41      * @javadoc
42      */

43     static Map modules;
44
45     private static final Logger log = Logging.getLoggerInstance(Module.class);
46
47     /**
48      * This function returns the Module's version number as an Integer.
49      * It takes no parameters.
50      * This function can be called through the function framework.
51      * @since MMBase-1.8
52      */

53     protected Function getVersionFunction = new AbstractFunction("getVersion", Parameter.EMPTY, ReturnType.INTEGER) {
54         public Object JavaDoc getFunctionValue(Parameters arguments) {
55             return new Integer JavaDoc(getVersion());
56         }
57     };
58
59     /**
60      * This function returns the Module's maintainer as a String.
61      * It takes no parameters.
62      * This function can be called through the function framework.
63      * @since MMBase-1.8
64      */

65     protected Function getMaintainerFunction = new AbstractFunction("getMaintainer", Parameter.EMPTY, ReturnType.STRING) {
66         public Object JavaDoc getFunctionValue(Parameters arguments) {
67             return getMaintainer();
68         }
69     };
70
71     String JavaDoc moduleName = null;
72     Hashtable state = new Hashtable();
73     Hashtable properties; // would like this to be LinkedHashMap (predictable order)
74
String JavaDoc maintainer;
75     int version;
76
77     // startup call.
78
private boolean started = false;
79
80     public Module() {
81         addFunction(getVersionFunction);
82         addFunction(getMaintainerFunction);
83         String JavaDoc startedAt = (new Date(System.currentTimeMillis())).toString();
84         state.put("Start Time", startedAt);
85     }
86
87     public final void setName(String JavaDoc name) {
88         if (moduleName == null) {
89             moduleName = name;
90         }
91     }
92
93     /**
94      * @since MMBase-1.8
95      */

96     public static ResourceLoader getModuleLoader() {
97         return ResourceLoader.getConfigurationRoot().getChildResourceLoader("modules");
98     }
99
100     /**
101      * @since MMBase-1.8
102      */

103     public static ModuleReader getModuleReader(String JavaDoc moduleName) {
104         try {
105             InputSource is = getModuleLoader().getInputSource(moduleName + ".xml");
106             if (is == null) return null;
107             return new ModuleReader(is);
108         } catch (Exception JavaDoc e) {
109             log.error(e);
110             return null;
111         }
112     }
113
114     /**
115      * Starts the module.
116      * This module calls the {@link #init()} of a module exactly once.
117      * In other words, once the init() is called, it does not call it again.
118      * This method is final and cannot be overridden.
119      * It is used to safely initialize modules during startup, and allows other modules
120      * to force the 'startup' of another module without risk.
121      */

122     public final void startModule() {
123         if (started) return;
124         synchronized(Module.class) {
125             init();
126             started = true;
127         }
128     }
129
130     /**
131      * Returns whether the module has started (has been initialized or is in
132      * its initialization fase).
133      */

134     public final boolean hasStarted() {
135         return started;
136     }
137
138     /**
139      * Initializes the module.
140      * Init must be overridden to read the environment variables it needs.
141      * <br />
142      * This method is called by {@link #startModule()}, which makes sure it is not called
143      * more than once. You should not call init() directly, call startModule() instead.
144      */

145     public void init() {
146     }
147
148     /**
149      * prepares the module when loaded.
150      * Onload must be overridden to execute methods that need to be performed when the module
151      * is loaded but before any other modules are initailized.
152      * <br />
153      * This method is called by {@link #startModules()}. You should not call onload() directly.
154      * @scope protected
155      */

156     public void onload() {
157     }
158
159     /**
160      * Shuts down the module. This method is called by shutdownModules.
161      *
162      * @since MMBase-1.6.2
163      */

164     protected void shutdown() {
165         // on default, nothing needs to be done.
166
}
167
168     /**
169      * state, returns the state hashtable that is/can be used to debug. Should
170      * be overridden when live state should be done.
171      */

172     public Hashtable state() {
173         return state;
174     }
175
176     /**
177      * Sets an init-parameter key-value pair
178      */

179     public void setInitParameter(String JavaDoc key,String JavaDoc value) {
180         if (properties != null) {
181             properties.put(key, value);
182         }
183     }
184
185     /**
186      * Gets an init-parameter key-value pair
187      */

188     public String JavaDoc getInitParameter(String JavaDoc key) {
189         if (properties != null) {
190             String JavaDoc value=(String JavaDoc)properties.get(key);
191             if (value == null) {
192                 key = key.toLowerCase();
193                 value = (String JavaDoc)properties.get(key);
194                 // try the system property, set on the JVM commandline
195
// i.e. you could provide a value for the mmbaseroot "machinename" property by specifying:
196
// -Dmmbaseroot.machinename=myname
197
if (value == null) {
198                     value = System.getProperty(moduleName+"."+key);
199                 }
200             }
201             return value;
202         } else {
203             log.error("getInitParameters(" + key + "): No properties found, called before they where loaded");
204         }
205         return null;
206     }
207
208     /**
209      * Returns the properties to the subclass.
210      */

211     protected Hashtable getProperties(String JavaDoc propertytable) {
212         //String filename="/usr/local/vpro/james/adminopen/modules/";
213
//return results;
214
return null;
215         //return Environment.getProperties(this,propertytable);
216
}
217
218     /**
219      * Returns one propertyvalue to the subclass.
220      */

221     protected String JavaDoc getProperty(String JavaDoc name, String JavaDoc var) {
222         return "";
223     }
224
225     /**
226      * Gets own modules properties
227      */

228     public Hashtable getInitParameters() {
229         return properties;
230     }
231
232     /**
233      * override properties through application context
234      * @param contextPath path in application context where properties are located
235      * @since MMBase 1.8.2
236      */

237     public void loadInitParameters(String JavaDoc contextPath) {
238         try {
239             Map contextMap = ApplicationContextReader.getProperties(contextPath);
240             if (!contextMap.isEmpty()) {
241                 properties.putAll(contextMap);
242             }
243         } catch (javax.naming.NamingException JavaDoc ne) {
244             log.debug("Can't obtain properties from application context: " + ne.getMessage());
245         }
246     }
247
248     
249     /**
250      * Returns an iterator of all the modules that are currently active.
251      * This function <code>null</code> if no attempt has the modules have (not) yet been to loaded.
252      * Unlike {@link #getModule}, this method does not automatically load modules if this hadn't occurred yet.
253      * @return an <code>Iterator</code> with all active modules
254      */

255     public static final Iterator getModules() {
256         if (modules == null) {
257             return null;
258         } else {
259             return modules.values().iterator();
260         }
261     }
262
263     /**
264      * Returns the name of the module
265      * @return the module name
266      */

267     public final String JavaDoc getName() {
268         return moduleName; // org.mmbase
269
}
270
271     /**
272      * provide some info on the module
273      */

274     public String JavaDoc getModuleInfo() {
275         return "No module info provided";
276     }
277
278     /**
279      * maintainance call called by the admin module every x seconds.
280      */

281     public void maintainance() {
282     }
283
284
285     /**
286      * Calls shutdown of all registered modules.
287      *
288      * @since MMBase-1.6.2
289      */

290     public static synchronized final void shutdownModules() {
291         Iterator i = getModules();
292         while (i != null && i.hasNext()) {
293             Module m = (Module) i.next();
294             log.service("Shutting down " + m.getName());
295             m.shutdown();
296             log.service("Shut down " + m.getName());
297         }
298         modules = null;
299     }
300
301     public static synchronized final void startModules() {
302         // call the onload to get properties
303
log.service("Starting modules " + modules.keySet());
304         for (Iterator i = modules.values().iterator(); i.hasNext();) {
305             if (Thread.currentThread().isInterrupted()) {
306                 log.info("Interrupted");
307                 return;
308             }
309             Module mod = (Module)i.next();
310             if( log.isDebugEnabled() ) {
311                 log.debug("startModules(): modules.onload(" + mod + ")");
312             }
313             try {
314                 mod.onload();
315             } catch (Exception JavaDoc f) {
316                 log.warn("startModules(): modules(" + mod + ") not found to 'onload'!", f);
317             }
318         }
319         // so now really give em their init
320
if (log.isDebugEnabled()) {
321             log.debug("startModules(): init the modules(" + modules + ")");
322         }
323         for (Iterator i = modules.values().iterator(); i.hasNext();) {
324             if (Thread.currentThread().isInterrupted()) {
325                 log.info("Interrupted");
326                 return;
327             }
328             Module mod = (Module) i.next();
329             log.info("Starting module " + mod.getName());
330             if ( log.isDebugEnabled()) {
331                 log.debug("startModules(): mod.startModule(" + mod + ")");
332             }
333             try {
334                 mod.startModule();
335             } catch (Exception JavaDoc f) {
336                 log.error("startModules(): module(" + mod + ") not found to 'init'!: " + f.getClass() + ": " + f.getMessage());
337                 log.error(Logging.stackTrace(f));
338             }
339         }
340     }
341
342     public static boolean hasModule(String JavaDoc name) {
343         boolean check = modules.containsKey(name.toLowerCase());
344         if (!check) {
345             check = modules.containsKey(name);
346         }
347         return check;
348     }
349     
350     /**
351      * Retrieves a reference to a Module.
352      * This call does not ensure that the requested module has been initialized.
353      *
354      * @param name the name of the module to retrieve
355      * @return a refernce to a <code>Module</code>, or <code>null</code> if the
356      * module does not exist or is inactive.
357      */

358     public static Module getModule(String JavaDoc name) {
359         return getModule(name, false);
360     }
361
362     /**
363      * Retrieves a reference to a Module.
364      * If you set the <code>startOnLoad</code> to <code>true</code>,
365      * this call ensures that the requested module has been initialized by
366      * calling the {@link #startModule()} method.
367      * This is needed if you need to call Module methods from the init() of
368      * another module.
369      *
370      *
371      * @param name the name of the module to retrieve
372      * @param startOnLoad if true, the code makes sure the module has been started
373      * @return a reference to a <code>Module</code>, or <code>null</code> if the
374      * module does not exist or is inactive.
375      */

376     public static Module getModule(String JavaDoc name, boolean startOnLoad) {
377         // are the modules loaded yet ? if not load them
378
synchronized(Module.class) {
379                 if (modules == null) { // still null after obtaining lock
380
log.service("Loading MMBase modules...");
381                     modules = loadModulesFromDisk();
382                     if (log.isDebugEnabled()) {
383                         log.debug("getModule(" + name + "): Modules not loaded, loading them..");
384                     }
385                     startModules();
386                     // also start the maintaince thread that calls all modules 'maintanance' method every x seconds
387
new ModuleProbe().start();
388                 }
389             }
390         // try to obtain the ref to the wanted module
391
Module obj = (Module) modules.get(name.toLowerCase());
392         if (obj == null) { // try case sensitivily as well?
393
obj = (Module) modules.get(name);
394         }
395         if (obj != null) {
396             // make sure the module is started, as this method could
397
// have been called from the init() of another Module
398
if (startOnLoad) {
399                 obj.startModule();
400             }
401             return obj;
402         } else {
403             log.warn("The module '" + name + "' could not be found!");
404             return null;
405         }
406     }
407
408     public String JavaDoc getMaintainer() {
409         return maintainer;
410     }
411
412     public void setMaintainer(String JavaDoc m) {
413         maintainer = m;
414     }
415
416     public void setVersion(int v) {
417         version = v;
418     }
419
420     public int getVersion() {
421         return version;
422     }
423
424     /**
425      * Loads all module-xml present in <mmbase-config-dir>/modules.
426      * @return A HashTable with <module-name> --> Module-instance
427      * @scope private (only called from getModule)
428      */

429     private static synchronized Hashtable loadModulesFromDisk() {
430         Hashtable results = new Hashtable();
431         ResourceLoader moduleLoader = getModuleLoader();
432         Collection modules = moduleLoader.getResourcePaths(ResourceLoader.XML_PATTERN, false/* non-recursive*/);
433         log.info("In " + moduleLoader + " the following module XML's were found " + modules);
434         Iterator i = modules.iterator();
435         while (i.hasNext()) {
436             String JavaDoc file = (String JavaDoc) i.next();
437             String JavaDoc fileName = ResourceLoader.getName(file);
438             ModuleReader parser = null;
439             try {
440                 InputSource is = moduleLoader.getInputSource(file);
441                 if (is != null) parser = new ModuleReader(is);
442             } catch (Exception JavaDoc e) {
443                 log.error(e);
444             }
445             if (parser != null && parser.getStatus().equals("active")) {
446                 String JavaDoc className = parser.getClassName();
447                 // try starting the module and give it its properties
448
try {
449                     log.service("Loading module " + fileName + " with class " + className);
450                     Module mod;
451                     if (parser.getURLString() != null){
452                         log.service("loading module from jar " + parser.getURLString());
453                         URL url = new URL(parser.getURLString());
454                         URLClassLoader c = new URLClassLoader(new URL[]{url}, Module.class.getClassLoader());
455                         Class JavaDoc newClass = c.loadClass(className);
456                         mod = (Module) newClass.newInstance();
457                     } else {
458                         Class JavaDoc newClass = Class.forName(className);
459                         mod = (Module) newClass.newInstance();
460                     }
461
462                     results.put(fileName, mod);
463
464                     mod.properties = new Hashtable(parser.getProperties());
465
466                     // set the module name property using the module's filename
467
// maybe we need a parser.getName() function to improve on this
468
mod.setName(fileName);
469
470                     mod.setMaintainer(parser.getMaintainer());
471                     mod.setVersion(parser.getVersion());
472                 } catch (ClassNotFoundException JavaDoc cnfe) {
473                     log.error("Could not load class with name '" + className + "', " +
474                               "which was specified in the module:'" + file + " '(" + cnfe + ")" );
475                 } catch (Throwable JavaDoc e) {
476                     log.error("Error while loading module class" + Logging.stackTrace(e));
477                 }
478             }
479         }
480         return results;
481     }
482
483 }
484
Popular Tags