KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > loader > ClassEntry


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.loader;
31
32 import com.caucho.log.Log;
33 import com.caucho.make.DependencyContainer;
34 import com.caucho.util.ByteBuffer;
35 import com.caucho.util.QDate;
36 import com.caucho.vfs.Depend;
37 import com.caucho.vfs.Dependency;
38 import com.caucho.vfs.JarPath;
39 import com.caucho.vfs.Path;
40 import com.caucho.vfs.PersistentDependency;
41 import com.caucho.vfs.ReadStream;
42
43 import java.io.IOException JavaDoc;
44 import java.lang.ref.WeakReference JavaDoc;
45 import java.security.CodeSource JavaDoc;
46 import java.util.logging.Level JavaDoc;
47 import java.util.logging.Logger JavaDoc;
48
49 /**
50  * Describes a cached loaded class entry.
51  */

52 public class ClassEntry implements Dependency {
53   private static final Logger JavaDoc log = Log.open(ClassEntry.class);
54   
55   private static boolean _hasJNIReload;
56   private static boolean _hasAnnotations;
57
58   private DynamicClassLoader _loader;
59   private String JavaDoc _name;
60     
61   private Path _classPath;
62
63   private PersistentDependency _depend;
64
65   private boolean _classIsModified;
66     
67   private Path _sourcePath;
68   private long _sourceLastModified;
69   private long _sourceLength;
70
71   private ClassPackage _classPackage;
72
73   private CodeSource JavaDoc _codeSource;
74
75   private ClassNotFoundException JavaDoc _exn;
76     
77   private WeakReference JavaDoc<Class JavaDoc> _clRef;
78
79   /**
80    * Create a loaded class entry
81    *
82    * @param name the classname
83    * @param sourcePath path to the source Java file
84    * @param classPath path to the compiled class file
85    */

86   public ClassEntry(DynamicClassLoader loader,
87                     String JavaDoc name, Path sourcePath,
88                     Path classPath,
89             CodeSource JavaDoc codeSource)
90   {
91     _loader = loader;
92     _name = name;
93
94     _classPath = classPath;
95
96     setDependPath(classPath);
97
98     if (sourcePath != null && ! sourcePath.equals(classPath)) {
99       _sourcePath = sourcePath;
100       
101       _sourceLastModified = sourcePath.getLastModified();
102       _sourceLength = sourcePath.getLength();
103     }
104
105     _codeSource = codeSource;
106
107     /*
108     if (codePath == null)
109       codePath = classPath;
110
111     if (_loader.getSecurityManager() != null) {
112       try {
113         _codeSource = new CodeSource(new URL(codePath.getURL()), null);
114       } catch (Exception e) {
115         e.printStackTrace();
116       }
117     }
118     */

119   }
120
121   /**
122    * Create a loaded class entry
123    *
124    * @param name the classname
125    * @param sourcePath path to the source Java file
126    * @param classPath path to the compiled class file
127    */

128   public ClassEntry(Loader loader,
129                     String JavaDoc name, Path sourcePath,
130                     Path classPath)
131   {
132     this(loader.getLoader(), name, sourcePath, classPath,
133      loader.getCodeSource(classPath));
134   }
135
136   public String JavaDoc getName()
137   {
138     return _name;
139   }
140
141   /**
142    * returns the class loader.
143    */

144   public DynamicClassLoader getClassLoader()
145   {
146     return _loader;
147   }
148
149   public CodeSource JavaDoc getCodeSource()
150   {
151     return _codeSource;
152   }
153
154   public Path getSourcePath()
155   {
156     return _sourcePath;
157   }
158
159   /**
160    * Sets the depend path.
161    */

162   protected void setDependPath(Path dependPath)
163   {
164     if (dependPath instanceof JarPath)
165       _depend = ((JarPath) dependPath).getDepend();
166     else
167       _depend = new Depend(dependPath);
168   }
169
170   /**
171    * Adds the dependencies, returning true if it's adding itself.
172    */

173   protected boolean addDependencies(DependencyContainer container)
174   {
175     if (_classPath instanceof JarPath) {
176       container.add(_depend);
177       return false;
178     }
179     else if (_hasJNIReload) {
180       container.add(this);
181       return true;
182     }
183     else if (_sourcePath == null) {
184       container.add(_depend);
185       return false;
186     }
187     else {
188       container.add(this);
189       return true;
190     }
191   }
192   
193   public void setSourceLength(long length)
194   {
195     _sourceLength = length;
196   }
197   
198   public void setSourceLastModified(long lastModified)
199   {
200     _sourceLastModified = lastModified;
201   }
202   
203   public ClassPackage getClassPackage()
204   {
205     return _classPackage;
206   }
207
208   public void setClassPackage(ClassPackage pkg)
209   {
210     _classPackage = pkg;
211   }
212
213   /**
214    * Returns true if the source file has been modified.
215    */

216   public boolean isModified()
217   {
218     if (_depend.isModified()) {
219       if (log.isLoggable(Level.FINE))
220         log.fine("class modified: " + _depend);
221
222       return reloadIsModified();
223     }
224     else if (_sourcePath == null)
225       return false;
226       
227     else if (_sourcePath.getLastModified() != _sourceLastModified) {
228       if (log.isLoggable(Level.FINE))
229         log.fine("source modified time: " + _sourcePath +
230                  " old:" + QDate.formatLocal(_sourceLastModified) +
231                  " new:" + QDate.formatLocal(_sourcePath.getLastModified()));
232
233       if (! compileIsModified()) {
234     return false;
235       }
236       
237       boolean isModified = reloadIsModified();
238
239       return isModified;
240     }
241     else if (_sourcePath.getLength() != _sourceLength) {
242       if (log.isLoggable(Level.FINE))
243         log.fine("source modified length: " + _sourcePath +
244                  " old:" + _sourceLength +
245                  " new:" + _sourcePath.getLength());
246
247       if (! compileIsModified())
248     return false;
249
250       return reloadIsModified();
251     }
252     else {
253       return false;
254     }
255   }
256
257   /**
258    * Returns true if the compile doesn't avoid the dependency.
259    */

260   public boolean compileIsModified()
261   {
262     return true;
263   }
264
265   /**
266    * Returns true if the reload doesn't avoid the dependency.
267    */

268   public boolean reloadIsModified()
269   {
270     if (_classIsModified) {
271       return true;
272     }
273
274     if (! _hasJNIReload || ! _classPath.canRead()) {
275       return true;
276     }
277     
278     try {
279       long length = _classPath.getLength();
280
281       Class JavaDoc cl = _clRef != null ? _clRef.get() : null;
282     
283       if (cl == null) {
284     return false;
285       }
286
287       if (_hasAnnotations && requireReload(cl))
288     return true;
289         
290       ReadStream is = _classPath.openRead();
291
292       byte []bytecode = new byte[(int) length];
293         
294       try {
295     is.readAll(bytecode, 0, bytecode.length);
296       } finally {
297     is.close();
298       }
299
300       int result = reloadNative(cl, bytecode, 0, bytecode.length);
301     
302       if (result != 0) {
303     _classIsModified = true;
304     return true;
305       }
306
307       setDependPath(_classPath);
308       
309       if (_sourcePath != null) {
310     _sourceLastModified = _sourcePath.getLastModified();
311     _sourceLength = _sourcePath.getLength();
312       }
313
314       log.info("Reloading " + cl.getName());
315
316       return false;
317     } catch (Exception JavaDoc e) {
318       log.log(Level.WARNING, e.toString(), e);
319       _classIsModified = true;
320
321       return true;
322     }
323   }
324
325   /**
326    * Returns the path to the class file.
327    */

328   public Path getClassPath()
329   {
330     return _classPath;
331   }
332
333   public Class JavaDoc getEntryClass()
334   {
335     return _clRef != null ? _clRef.get() : null;
336   }
337
338   public void setEntryClass(Class JavaDoc cl)
339   {
340     _clRef = new WeakReference JavaDoc<Class JavaDoc>(cl);
341   }
342
343   /**
344    * preload actions.
345    */

346   public void preLoad()
347     throws ClassNotFoundException JavaDoc
348   {
349   }
350
351   /**
352    * Loads the contents of the class file into the buffer.
353    */

354   public void load(ByteBuffer buffer)
355     throws IOException JavaDoc
356   {
357     Path classPath = getClassPath();
358     
359     buffer.clear();
360     long length = classPath.getLength();
361     if (length < 0)
362       throw new IOException JavaDoc("missing class: " + classPath);
363     ReadStream is = classPath.openRead();
364     try {
365       buffer.setLength((int) length);
366       if (is.readAll(buffer.getBuffer(), 0, (int) length) != length)
367         throw new IOException JavaDoc("class file length mismatch");
368     } finally {
369       is.close();
370     }
371   }
372
373   /**
374    * post-load actions.
375    */

376   public boolean postLoad()
377   {
378     return false;
379   }
380
381   public static boolean hasJNIReload()
382   {
383     return _hasJNIReload;
384   }
385
386   private static boolean requireReload(Class JavaDoc cl)
387   {
388     return cl.isAnnotationPresent(RequireReload.class);
389   }
390
391   public String JavaDoc toString()
392   {
393     if (_sourcePath == null)
394       return "ClassEntry[" + _classPath + "]";
395     else
396       return "ClassEntry[" + _classPath + ", SRC=" + _sourcePath + "]";
397   }
398
399   public static native boolean canReloadNative();
400
401   public static native int reloadNative(Class JavaDoc cl,
402                         byte []bytes, int offset, int length);
403
404   class ReloadThread implements Runnable JavaDoc {
405     private volatile boolean _isDone;
406
407     public boolean isDone()
408     {
409       return _isDone;
410     }
411     
412     public void run()
413     {
414     }
415   }
416   
417   static {
418     try {
419       System.loadLibrary("resin_os");
420       _hasJNIReload = canReloadNative();
421       if (_hasJNIReload)
422     log.config("In-place class redefinition (HotSwap) is available.");
423       else
424     log.config("In-place class redefinition (HotSwap) is not available. In-place class reloading during development requires a compatible JDK and -Xdebug.");
425     } catch (Throwable JavaDoc e) {
426       log.fine(e.toString());
427       
428       log.log(Level.FINEST, e.toString(), e);
429       // log.config("In-place class redefinition (HotSwap) is not available.\n" + e);
430
}
431     
432     try {
433       Class JavaDoc reloadClass = Class.forName("com.caucho.loader.RequireReload");
434       
435       Object JavaDoc.class.getAnnotation(reloadClass);
436
437       _hasAnnotations = true;
438     } catch (Throwable JavaDoc e) {
439     }
440   }
441 }
442
Popular Tags