KickJava   Java API By Example, From Geeks To Geeks.

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


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.BufferedReader JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.InputStreamReader JavaDoc;
25 import java.net.URL JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Vector JavaDoc;
29
30
31 /**
32  * A group of modules and libraries.
33  *
34  * Modules can have one or more jars and class dirs. Classloaders are created
35  * from modules when the module is started are be disposed when the module is stopped.
36  *
37  * The module will delegate to the associated repository in addition to the
38  * normal delegation rules. The repository will search on all sibling modules.
39  * This mechanism is defined in the MLetClassLoader and is also used by JBoss and
40  * few other servers.
41  *
42  * TODO: explain more ( or point to the right jboss/mlet pages )
43  * TODO: explain how this can be used for webapps to support better partitioning
44  *
45  * @author Costin Manolache
46  */

47 public class Repository {
48    
49     private static final boolean DEBUG=true; //LoaderProperties.getProperty("loader.Repository.debug") != null;
50

51     // Allows the (experimental) use of jar indexes
52
// Right now ( for small set of jars, incomplete build ) it's a tiny 3.5 -> 3.4 sec dif.
53
private static final boolean USE_IDX=true;// //LoaderProperties.getProperty("loader.Repository.useIdx") != null;
54

55     private Vector JavaDoc loaders=new Vector JavaDoc();
56     private String JavaDoc name;
57     private Vector JavaDoc grpModules=new Vector JavaDoc();
58     private transient Loader loader;
59     
60     private Repository parent;
61
62     private transient ModuleClassLoader groupClassLoader;
63     private Hashtable JavaDoc prefixes=new Hashtable JavaDoc();
64
65     public Repository() {
66     }
67
68     public Repository(Loader loader) {
69         if( loader== null ) throw new NullPointerException JavaDoc();
70         this.loader=loader;
71     }
72
73     public Loader getLoader() {
74         return loader;
75     }
76     
77     public void addModule( Module mod ) {
78         mod.setRepository( this );
79
80         grpModules.addElement(mod);
81         if( loader.listener!=null ) {
82             loader.listener.moduleAdd(mod);
83         }
84
85         if(! mod.isStarted()) {
86             mod.start();
87             //log("started " + mod);
88
} else {
89             //log("already started " + mod);
90
}
91         
92         try {
93             if( USE_IDX ) {
94                 processJarIndex(mod);
95                 writeCacheIdx();
96             }
97         } catch (Exception JavaDoc e) {
98             // TODO Auto-generated catch block
99
e.printStackTrace();
100         }
101         
102     }
103     
104     public Enumeration JavaDoc getModules() {
105         return grpModules.elements();
106     }
107     
108     public Repository getParent() {
109         return parent;
110     }
111
112     /**
113      *
114      * @param parent The parent group
115      */

116     public void setParent(Repository parent) {
117         this.parent = parent;
118     }
119
120     /** Add a class loder to the group.
121      *
122      * If this is a StandardClassLoader instance, it will be able to delegate
123      * to the group.
124      *
125      * If it's a regular ClassLoader - it'll be searched for classes, but
126      * it will not be able to delegate to peers.
127      *
128      * In future we may fine tune this by using manifests.
129      */

130     void addClassLoader(ClassLoader JavaDoc cl ) {
131         if( ( cl instanceof ModuleClassLoader )) {
132             ((ModuleClassLoader)cl).setRepository(this);
133         }
134         loaders.addElement(cl);
135         // log("Adding classloader " + cl);
136
}
137
138     public String JavaDoc getName() {
139         return name;
140     }
141
142     public void removeClassLoader(ClassLoader JavaDoc cl) {
143         int oldSize=loaders.size();
144         loaders.removeElement(cl);
145
146         if(DEBUG) log("removed " + loaders.size() + "/" + oldSize + ": " + cl);
147     }
148
149     /** Return a class loader associated with the group.
150      * This will delegate to all modules in the group, then to parent.
151      *
152      * @return
153      */

154     public ClassLoader JavaDoc getClassLoader() {
155         if( groupClassLoader==null ) {
156             if( parent == null ) {
157                 groupClassLoader=new ModuleClassLoader(new URL JavaDoc[0]);
158             } else {
159                 groupClassLoader=new ModuleClassLoader(new URL JavaDoc[0], parent.getClassLoader());
160             }
161             groupClassLoader.start();
162             groupClassLoader.setRepository(this);
163         }
164         return groupClassLoader;
165     }
166     /**
167      * Find a class in the group. It'll iterate over each loader
168      * and try to find the class - using only the method that
169      * search locally or on parent ( i.e. not in group, to avoid
170      * recursivity ).
171      *
172      *
173      * @param classN
174      * @return
175      */

176     public Class JavaDoc findClass(ClassLoader JavaDoc caller, String JavaDoc classN ) {
177         Class JavaDoc clazz=null;
178         
179         // do we have it in index ?
180
if( USE_IDX ) {
181         int lastIdx=classN.lastIndexOf(".");
182         String JavaDoc prefix=(lastIdx>0) ? classN.substring(0, lastIdx) : classN;
183         Object JavaDoc mO=prefixes.get(prefix.replace('.', '/'));
184         if( mO!=null ) {
185             if( mO instanceof Module ) {
186                 Module m=(Module)mO;
187                 try {
188                     Class JavaDoc c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
189                     //log("Prefix: " +prefix + " " + classN + " " + m);
190
return c;
191                 } catch (Exception JavaDoc e) {
192                     //log("Prefix err: " +prefix + " " + classN + " " + m + " " + e);
193
//return null;
194
}
195             } else {
196                 Module mA[]=(Module[])mO;
197                 for( int i=0; i<mA.length; i++ ) {
198                     Module m=mA[i];
199                     try {
200                         Class JavaDoc c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
201                         //log("Prefix: " +prefix + " " + classN + " " + m);
202
return c;
203                     } catch (Exception JavaDoc e) {
204                         //log("Prefix err: " +prefix + " " + classN + " " + m + " " + e);
205
//return null;
206
}
207                 }
208             }
209         }
210         }
211
212         // TODO: move the vector to a []
213
for( int i=loaders.size()-1; i>=0; i-- ) {
214             
215             // TODO: for regular CL, just use loadClass, they'll not recurse
216
// The behavior for non-SCL or not in the group loader is the same as for parent loader
217
ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
218             // TODO: move loaders with index in separate vector
219
//if( cl.getModule().hasIndex ) continue;
220
if( cl== caller ) continue;
221             //if( classN.indexOf("SmtpCoyoteProtocolHandler") > 0 ) {
222
//log("try " + cl.debugObj + " " + name + " " + classN + " " + loaders.size());
223
//}
224
try {
225                 if( cl instanceof ModuleClassLoader ) {
226                     clazz=((ModuleClassLoader)cl).findLocalClass(classN );
227                 } else {
228                     clazz=cl.findClass(classN);
229                 }
230
231                 //System.err.println("GRPLD: " + classN + " from " + info.get(cl));
232
return clazz;
233             } catch (ClassNotFoundException JavaDoc e) {
234                 //System.err.println("CNF: " + classN + " " + info.get(cl) );
235
//if( classN.indexOf("smtp") > 0 ) e.printStackTrace();
236
}
237         }
238         return null;
239     }
240     
241     /**
242      * @param loader
243      * @param name2
244      * @return
245      */

246     public URL JavaDoc findResource(ModuleClassLoader caller, String JavaDoc classN) {
247         URL JavaDoc url=null;
248         
249         for( int i=loaders.size()-1; i>=0; i-- ) {
250             // TODO: for regular CL, just use loadClass, they'll not recurse
251
// The behavior for non-SCL or not in the group loader is the same as for parent loader
252
ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
253             if( cl== caller ) continue;
254             url=((ModuleClassLoader)cl).findResource(classN );
255             if( url!=null )
256                 return url;
257         }
258         return null;
259     }
260
261     private void log(String JavaDoc s) {
262         System.err.println("Repository (" + name + "): " + s );
263     }
264
265     /**
266      * @param name2
267      */

268     public void setName(String JavaDoc name2) {
269         this.name=name2;
270     }
271
272     /*
273      * Work in progress:
274      *
275      * -use the INDEX.LIST to get prefixes to avoid linear
276      * search in repositories.
277      *
278      * - serialize the state ( including timestamps ) to improve startup time
279      * ( avoids the need to open all jars - if INDEX.LIST is ok)
280      */

281     
282     /**
283      * Read the index. The index contain packages and top level resources
284      *
285      * @param cl
286      * @throws Exception
287      */

288     private void processJarIndex(Module m) throws Exception JavaDoc {
289         ModuleClassLoader cl=(ModuleClassLoader)m.createClassLoader();
290         // only support index for modules with a single jar in CP
291
String JavaDoc cp=m.getClasspathString();
292         if( ! cp.endsWith(".jar")) return;
293         URL JavaDoc urlIdx=cl.findResource("META-INF/INDEX.LIST");
294         if( urlIdx == null ) {
295             log("INDEX.LIST not found, run: jar -i " + m.getClasspathString());
296             return;
297         }
298         try {
299             InputStream JavaDoc is=urlIdx.openStream();
300             if( is==null ) {
301                 log("Can't read " + urlIdx + " " + m.getClasspathString());
302                 return;
303             }
304             BufferedReader JavaDoc br=new BufferedReader JavaDoc( new InputStreamReader JavaDoc(is) );
305             String JavaDoc line=br.readLine();
306             if( line==null ) return;
307             if( ! line.startsWith( "JarIndex-Version:") ||
308                     ! line.endsWith("1.0")) {
309                 log("Invalid signature " + line + " " + m.getClasspathString());
310             }
311             br.readLine(); // ""
312

313             while( readSection(br, m) ) {
314             }
315            
316             m.hasIndex=true;
317         } catch (IOException JavaDoc e) {
318             // TODO Auto-generated catch block
319
e.printStackTrace();
320         }
321     }
322     
323     private boolean readSection( BufferedReader JavaDoc br, Module m) throws IOException JavaDoc {
324         String JavaDoc jarName=br.readLine();
325         if( jarName==null ) return false; // done
326
if( "".equals( jarName )) {
327             log("Invalid jarName " + jarName + " " + m.getClasspathString() );
328             return false;
329         }
330         //log("Index " + jarName + " " + m.getClasspathString());
331
String JavaDoc prefix=null;
332         while( ((prefix=br.readLine()) != null ) &&
333                 (! "".equals( prefix )) ) {
334             //log("found " + prefix + " " + m);
335
Object JavaDoc o=prefixes.get(prefix);
336             if( o == null ) {
337                 prefixes.put(prefix, m);
338             } else {
339                 Module mA[]=null;
340                 if( o instanceof Module ) {
341                     mA=new Module[2];
342                     mA[0]=(Module)o;
343                     mA[1]=m;
344                 } else {
345                     Object JavaDoc oldA[]=(Module[])o;
346                     mA=new Module[oldA.length + 1];
347                     System.arraycopy(oldA, 0, mA, 0, oldA.length);
348                     mA[oldA.length]=m;
349                 }
350                 prefixes.put( prefix, mA);
351                 //log("Multiple prefixes: " + prefix + " " + mA);
352

353             }
354         }
355         
356         return prefix!=null;
357     }
358
359
360     /** Read loader.REPO.cache from work dir
361      *
362      * This file will hold timestamps for each module/jar and cache the INDEX -
363      * to avoid opening the jars/modules that are not used
364      *
365      * @throws IOException
366      */

367     private void readCachedIdx() throws IOException JavaDoc {
368         
369     }
370     
371     /** Check the index and verify that:
372      * - all jars are older than timestamp and still exist
373      * - there are no new jars
374      *
375      * @throws IOException
376      */

377     private void checkCacheIdx() throws IOException JavaDoc {
378         
379     }
380     
381     
382     private void writeCacheIdx() throws IOException JavaDoc {
383         
384     }
385 }
386
Popular Tags