1 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 ; 44 import java.lang.ref.WeakReference ; 45 import java.security.CodeSource ; 46 import java.util.logging.Level ; 47 import java.util.logging.Logger ; 48 49 52 public class ClassEntry implements Dependency { 53 private static final Logger log = Log.open(ClassEntry.class); 54 55 private static boolean _hasJNIReload; 56 private static boolean _hasAnnotations; 57 58 private DynamicClassLoader _loader; 59 private String _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 _codeSource; 74 75 private ClassNotFoundException _exn; 76 77 private WeakReference <Class > _clRef; 78 79 86 public ClassEntry(DynamicClassLoader loader, 87 String name, Path sourcePath, 88 Path classPath, 89 CodeSource 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 119 } 120 121 128 public ClassEntry(Loader loader, 129 String name, Path sourcePath, 130 Path classPath) 131 { 132 this(loader.getLoader(), name, sourcePath, classPath, 133 loader.getCodeSource(classPath)); 134 } 135 136 public String getName() 137 { 138 return _name; 139 } 140 141 144 public DynamicClassLoader getClassLoader() 145 { 146 return _loader; 147 } 148 149 public CodeSource getCodeSource() 150 { 151 return _codeSource; 152 } 153 154 public Path getSourcePath() 155 { 156 return _sourcePath; 157 } 158 159 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 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 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 260 public boolean compileIsModified() 261 { 262 return true; 263 } 264 265 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 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 e) { 318 log.log(Level.WARNING, e.toString(), e); 319 _classIsModified = true; 320 321 return true; 322 } 323 } 324 325 328 public Path getClassPath() 329 { 330 return _classPath; 331 } 332 333 public Class getEntryClass() 334 { 335 return _clRef != null ? _clRef.get() : null; 336 } 337 338 public void setEntryClass(Class cl) 339 { 340 _clRef = new WeakReference <Class >(cl); 341 } 342 343 346 public void preLoad() 347 throws ClassNotFoundException 348 { 349 } 350 351 354 public void load(ByteBuffer buffer) 355 throws IOException 356 { 357 Path classPath = getClassPath(); 358 359 buffer.clear(); 360 long length = classPath.getLength(); 361 if (length < 0) 362 throw new IOException ("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 ("class file length mismatch"); 368 } finally { 369 is.close(); 370 } 371 } 372 373 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 cl) 387 { 388 return cl.isAnnotationPresent(RequireReload.class); 389 } 390 391 public String 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 cl, 402 byte []bytes, int offset, int length); 403 404 class ReloadThread implements Runnable { 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 e) { 426 log.fine(e.toString()); 427 428 log.log(Level.FINEST, e.toString(), e); 429 } 431 432 try { 433 Class reloadClass = Class.forName("com.caucho.loader.RequireReload"); 434 435 Object .class.getAnnotation(reloadClass); 436 437 _hasAnnotations = true; 438 } catch (Throwable e) { 439 } 440 } 441 } 442 | Popular Tags |