KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tomcat > util > loader > Loader


1 /*
2  * Copyright 1999,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18 package org.apache.tomcat.util.loader;
19
20
21 import java.io.File JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.net.MalformedURLException JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.StringTokenizer JavaDoc;
29 import java.util.Vector JavaDoc;
30
31
32 /**
33  * Boostrap loader for Catalina. This application constructs a class loader
34  * for use in loading the Catalina internal classes (by accumulating all of the
35  * JAR files found in the "server" directory under "catalina.home"), and
36  * starts the regular execution of the container. The purpose of this
37  * roundabout approach is to keep the Catalina internal classes (and any
38  * other classes they depend on, such as an XML parser) out of the system
39  * class path and therefore not visible to application level classes.
40  *
41  * @author Craig R. McClanahan
42  * @author Remy Maucherat
43  * @author Costin Manolache
44  */

45 public final class Loader {
46
47     private static final boolean DEBUG=true; //LoaderProperties.getProperty("loader.Loader.debug") != null;
48
private static final boolean FLAT=false;//LoaderProperties.getProperty("loader.Loader.flat") != null;
49

50     // -------------------------------------------------------------- Constants
51

52
53     protected static final String JavaDoc CATALINA_HOME_TOKEN = "${catalina.home}";
54     protected static final String JavaDoc CATALINA_BASE_TOKEN = "${catalina.base}";
55
56
57     // ------------------------------------------------------- Static Variables
58

59
60     /**
61      * Daemon object used by main.
62      */

63     private static Loader daemon = null;
64
65     // one should be enough
66
ModuleListener listener;
67
68
69     // -------------------------------------------------------------- Variables
70

71     protected Repository commonRepository = null;
72     protected Repository catalinaRepository = null;
73     protected Repository sharedRepository = null;
74
75     protected ClassLoader JavaDoc catalinaLoader = null;
76     private String JavaDoc[] args;
77     private Hashtable JavaDoc repositories=new Hashtable JavaDoc();
78     
79
80
81     // -------------------------------------------------------- Private Methods
82

83
84     private void initClassLoaders() {
85         try {
86             commonRepository = initRepository("common", null);
87             catalinaRepository = initRepository("server", commonRepository);
88             catalinaLoader = catalinaRepository.getClassLoader();
89             sharedRepository = initRepository("shared", commonRepository);
90         } catch (Throwable JavaDoc t) {
91             log("Class loader creation threw exception", t);
92             System.exit(1);
93         }
94     }
95
96     public Repository createRepository(String JavaDoc name, Repository parent) {
97         Repository lg=new Repository(this);
98
99         lg.setName(name);
100        
101         lg.setParent( parent );
102         
103         repositories.put(name, lg);
104         
105         if( listener != null ) {
106             listener.repositoryAdd(lg);
107         }
108         return lg;
109     }
110
111     public Enumeration JavaDoc getRepositoryNames() {
112         return repositories.keys();
113     }
114     
115     /** Create a module using the NAME.loader property to construct the
116      * classpath.
117      *
118      * @param name
119      * @param parent
120      * @return
121      * @throws Exception
122      */

123     private Repository initRepository(String JavaDoc name, Repository parent)
124         throws Exception JavaDoc
125     {
126         String JavaDoc value = LoaderProperties.getProperty(name + ".loader");
127
128         Repository lg=createRepository(name, parent );
129         if( DEBUG ) log( "Creating loading group " + name + " - " + value);
130         
131         if ((value == null) || (value.equals("")))
132             return lg;
133
134         ArrayList JavaDoc unpackedList = new ArrayList JavaDoc();
135         ArrayList JavaDoc packedList = new ArrayList JavaDoc();
136         ArrayList JavaDoc urlList = new ArrayList JavaDoc();
137
138         Vector JavaDoc repo=split( value );
139         Enumeration JavaDoc elems=repo.elements();
140         while (elems.hasMoreElements()) {
141             String JavaDoc repository = (String JavaDoc)elems.nextElement();
142
143             // Local repository
144
boolean packed = false;
145             if (repository.startsWith(CATALINA_HOME_TOKEN)) {
146                 repository = LoaderProperties.getCatalinaHome()
147                     + repository.substring(CATALINA_HOME_TOKEN.length());
148             } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
149                 repository = LoaderProperties.getCatalinaBase()
150                     + repository.substring(CATALINA_BASE_TOKEN.length());
151             }
152
153             // Check for a JAR URL repository
154
try {
155                 urlList.add(new URL JavaDoc(repository));
156                 continue;
157             } catch (MalformedURLException JavaDoc e) {
158                 // Ignore
159
}
160
161             if (repository.endsWith("*.jar")) {
162                 packed = true;
163                 repository = repository.substring
164                     (0, repository.length() - "*.jar".length());
165             }
166             if (packed) {
167                 packedList.add(new File JavaDoc(repository));
168             } else {
169                 unpackedList.add(new File JavaDoc(repository));
170             }
171         }
172
173         File JavaDoc[] unpacked = (File JavaDoc[]) unpackedList.toArray(new File JavaDoc[0]);
174         File JavaDoc[] packed = (File JavaDoc[]) packedList.toArray(new File JavaDoc[0]);
175         URL JavaDoc[] urls = (URL JavaDoc[]) urlList.toArray(new URL JavaDoc[0]);
176
177         // previously: ClassLoaderFactory.createClassLoader
178
initRepository(lg, unpacked, packed, urls, parent); //new ModuleGroup();
179

180         
181         // TODO: JMX registration for the group loader
182
/*
183         // Register the server classloader
184         ObjectName objectName =
185             new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
186         mBeanServer.registerMBean(classLoader, objectName);
187         */

188         
189         return lg; // classLoader;
190

191     }
192
193     /** Small hack to allow a loader.properties file to be passed in CLI, to
194      * allow a more convenient method to start with different params from
195      * explorer/kde/etc.
196      *
197      * If the first arg ends with ".loader", it is used as loader.properties
198      * file and removed from args[].
199      */

200     private void processCLI() {
201         if( args.length > 0 &&
202                 (args[0].toLowerCase().endsWith(".tomcat") ||
203                         args[0].toLowerCase().endsWith("loader.properties") )) {
204             String JavaDoc props=args[0];
205             String JavaDoc args2[]=new String JavaDoc[args.length-1];
206             System.arraycopy(args, 1, args2, 0, args2.length);
207             args=args2;
208             LoaderProperties.setPropertiesFile(props);
209         }
210     }
211     
212     /**
213      * Initialize:
214      * - detect the home/base directories
215      * - init the loaders / modules
216      * - instantiate the "startup" class(es)
217      *
218      */

219     public void main()
220         throws Exception JavaDoc
221     {
222         processCLI();
223         
224         // Set Catalina path
225
LoaderProperties.setCatalinaHome();
226         LoaderProperties.setCatalinaBase();
227
228         initClassLoaders();
229         
230         Thread.currentThread().setContextClassLoader(catalinaLoader);
231
232         securityPreload(catalinaLoader);
233
234         // Load our startup classes and call its process() method
235
/* Why multiple classes ?
236          * - maybe you want to start more "servers" ( tomcat ,something else )
237          * - easy hook for other load on startup modules ( like a jmx hook )
238          * - maybe split the loader-specific code from catalina
239          */

240         String JavaDoc startupClasses=LoaderProperties.getProperty("loader.auto-startup",
241                 "org.apache.catalina.startup.CatalinaModuleListener");
242         Vector JavaDoc v=split( startupClasses );
243         
244         for( int i=0; i<v.size(); i++ ) {
245             String JavaDoc startupCls=(String JavaDoc)v.elementAt(i);
246         
247             if (DEBUG)
248                 log("Loading startup class " + startupCls);
249             
250             Class JavaDoc startupClass =
251                 catalinaLoader.loadClass(startupCls);
252             
253             Object JavaDoc startupInstance = startupClass.newInstance();
254             
255             if( startupInstance instanceof ModuleListener ) {
256                 addModuleListener((ModuleListener)startupInstance);
257
258                 // it can get args[] and properties from Loader
259
listener.setLoader(this);
260                 
261                 // all arg processing moved there. Maybe we can make it consistent
262
// for all startup schemes
263
listener.start();
264             } else {
265                 Class JavaDoc paramTypes[] = new Class JavaDoc[0];
266                 Object JavaDoc paramValues[] = new Object JavaDoc[0];
267                 Method JavaDoc method =
268                     startupInstance.getClass().getMethod("execute", paramTypes);
269                 if( method==null )
270                     method = startupInstance.getClass().getMethod("start", paramTypes);
271                 method.invoke(startupInstance, paramValues);
272             }
273
274         }
275     }
276
277     public Repository getRepository( String JavaDoc name ) {
278         return (Repository)repositories.get(name);
279     }
280     
281     private static void securityPreload(ClassLoader JavaDoc loader)
282         throws Exception JavaDoc {
283
284         if( System.getSecurityManager() == null ){
285             return;
286         }
287
288         String JavaDoc value=LoaderProperties.getProperty("security.preload");
289         Vector JavaDoc repo=split( value );
290         Enumeration JavaDoc elems=repo.elements();
291         while (elems.hasMoreElements()) {
292             String JavaDoc classN = (String JavaDoc)elems.nextElement();
293             try {
294                 loader.loadClass( classN);
295             } catch( Throwable JavaDoc t ) {
296                 // ignore
297
}
298         }
299     }
300
301     // ----------------------------------------------------------- Main Program
302

303     public String JavaDoc[] getArgs() {
304         return args;
305     }
306
307     /**
308      * Main method.
309      *
310      * @param args Command line arguments to be processed
311      */

312     public static void main(String JavaDoc args[]) {
313         
314         try {
315             if (daemon == null) {
316                 daemon = new Loader();
317                 daemon.args=args;
318
319                 try {
320                     daemon.main();
321                 } catch (Throwable JavaDoc t) {
322                     t.printStackTrace();
323                     return;
324                 }
325             }
326         } catch (Throwable JavaDoc t) {
327             t.printStackTrace();
328         }
329
330     }
331
332     public void setCatalinaHome(String JavaDoc s) {
333         System.setProperty( "catalina.home", s );
334     }
335
336     public void setCatalinaBase(String JavaDoc s) {
337         System.setProperty( "catalina.base", s );
338     }
339
340     /**
341      * Public as ModuleClassLoader.
342      *
343      * @param cl
344      * @return
345      */

346     public Module getModule(ClassLoader JavaDoc cl ) {
347         if( cl instanceof ModuleClassLoader ) {
348             return ((ModuleClassLoader)cl).getModule();
349         }
350         return null;
351     }
352     
353     /**
354      * Create and return a new class loader, based on the configuration
355      * defaults and the specified directory paths:
356      *
357      * @param unpacked Array of pathnames to unpacked directories that should
358      * be added to the repositories of the class loader, or <code>null</code>
359      * for no unpacked directories to be considered
360      * @param packed Array of pathnames to directories containing JAR files
361      * that should be added to the repositories of the class loader,
362      * or <code>null</code> for no directories of JAR files to be considered
363      * @param urls Array of URLs to remote repositories, designing either JAR
364      * resources or uncompressed directories that should be added to
365      * the repositories of the class loader, or <code>null</code> for no
366      * directories of JAR files to be considered
367      * @param parent Parent class loader for the new class loader, or
368      * <code>null</code> for the system class loader.
369      *
370      * @exception Exception if an error occurs constructing the class loader
371      */

372     private void initRepository(Repository lg, File JavaDoc unpacked[],
373             File JavaDoc packed[], URL JavaDoc urls[], Repository parent)
374         throws Exception JavaDoc
375     {
376         StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
377
378         // Construct the "class path" for this class loader
379
ArrayList JavaDoc list = new ArrayList JavaDoc();
380         
381         // Add unpacked directories
382
if (unpacked != null) {
383             for (int i = 0; i < unpacked.length; i++) {
384                 File JavaDoc file = unpacked[i];
385                 if (!file.exists() || !file.canRead()) {
386                     if (DEBUG)
387                         log(" Not found: "+ file.getAbsolutePath());
388                     continue;
389                 }
390                 if (DEBUG)
391                     sb.append(" "+ file.getAbsolutePath());
392                 String JavaDoc cPath=file.getCanonicalPath();
393                 URL JavaDoc url=null;
394                 if( cPath.toLowerCase().endsWith(".jar") ||
395                         cPath.toLowerCase().endsWith(".zip") ) {
396                     url = new URL JavaDoc("file", null, cPath);
397                 } else {
398                     url = new URL JavaDoc("file", null, cPath + File.separator);
399                 }
400                 if( ! FLAT ) {
401                     addLoader(lg, parent, new URL JavaDoc[] { url });
402                 } else {
403                     list.add(url);
404                 }
405             }
406         }
407         
408         // Add packed directory JAR files
409
if (packed != null) {
410             for (int i = 0; i < packed.length; i++) {
411                 File JavaDoc directory = packed[i];
412                 if (!directory.isDirectory() || !directory.exists() ||
413                         !directory.canRead()) {
414                     if (DEBUG)
415                         log(" Not found: "+ directory.getAbsolutePath());
416                     continue;
417                 }
418                 String JavaDoc filenames[] = directory.list();
419                 for (int j = 0; j < filenames.length; j++) {
420                     String JavaDoc filename = filenames[j].toLowerCase();
421                     if (!filename.endsWith(".jar"))
422                         continue;
423                     File JavaDoc file = new File JavaDoc(directory, filenames[j]);
424                     if (DEBUG)
425                         sb.append(" "+ file.getAbsolutePath());
426                     URL JavaDoc url = new URL JavaDoc("file", null,
427                             file.getCanonicalPath());
428                     if( ! FLAT ) {
429                         addLoader(lg, parent, new URL JavaDoc[] { url });
430                     } else {
431                         list.add(url);
432                     }
433                 }
434             }
435         }
436         
437         // Add URLs
438
if (urls != null) {
439             for (int i = 0; i < urls.length; i++) {
440                 if( ! FLAT ) {
441                     addLoader(lg, parent, new URL JavaDoc[] { urls[i] });
442                 } else {
443                     list.add(urls[i]);
444                 }
445                 if (DEBUG)
446                     sb.append(" "+ urls[i]);
447             }
448         }
449         
450         // Construct the class loader itself
451

452         // TODO: experiment with loading each jar in a separate loader.
453
if (DEBUG)
454             log("Creating new class loader " + lg.getName() + " " + sb.toString());
455         
456         
457         URL JavaDoc[] array = (URL JavaDoc[]) list.toArray(new URL JavaDoc[list.size()]);
458         if( array.length > 0 ) {
459             addLoader(lg, parent, array);
460         }
461     }
462     
463     /**
464      * @param lg
465      * @param parent
466      * @param list
467      */

468     private void addLoader(Repository lg, Repository parent, URL JavaDoc array[])
469         throws Exception JavaDoc
470     {
471         Module module=new Module();
472         
473         module.setParent( parent );
474         module.setClasspath( array );
475         
476         lg.addModule(module);
477         
478     }
479
480     private static Vector JavaDoc split( String JavaDoc value ) {
481         Vector JavaDoc result=new Vector JavaDoc();
482         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(value, ",");
483         while (tokenizer.hasMoreElements()) {
484             String JavaDoc repository = tokenizer.nextToken();
485             repository.trim();
486             if( ! "".equals(repository) )
487                 result.addElement(repository);
488         }
489         return result;
490     }
491
492     void notifyModuleStart(Module module) {
493         if(listener!=null) listener.moduleStart(module);
494     }
495
496     void notifyModuleStop(Module module) {
497         listener.moduleStop(module);
498     }
499     
500     /** Add a module listener.
501      *
502      * To keep the dependencies minimal, the loader package only implements the
503      * basic class loading mechanism - but any advanced feature ( management,
504      * policy, etc ) should be implemented by a module.
505      *
506      * @param listener
507      */

508     public void addModuleListener(ModuleListener listener) {
509         this.listener=listener;
510     }
511
512     private static void log(String JavaDoc s) {
513         System.err.println("Main: " + s);
514     }
515     
516     private static void log( String JavaDoc msg, Throwable JavaDoc t ) {
517         System.err.println("Main: " + msg);
518         t.printStackTrace();
519     }
520
521 }
522
Popular Tags