1 26 27 package com.opensugar.cube.simple; 28 29 import com.opensugar.cube.BundleImpl; 30 import com.opensugar.cube.BundleClassLoader; 31 import com.opensugar.cube.Util; 32 import com.opensugar.cube.NamedPropertySet; 33 import com.opensugar.cube.java2.FileHelper; 34 35 import org.osgi.framework.FrameworkEvent; 36 37 import java.io.File ; 38 import java.io.InputStream ; 39 import java.io.IOException ; 40 import java.io.FileNotFoundException ; 41 import java.io.FileOutputStream ; 42 import java.io.FileInputStream ; 43 import java.io.DataInputStream ; 44 import java.net.URL ; 45 import java.net.MalformedURLException ; 46 import java.util.Hashtable ; 47 import java.util.Enumeration ; 48 import java.util.Vector ; 49 import java.util.zip.ZipFile ; 50 import java.util.zip.ZipEntry ; 51 52 public class SimpleBundleClassLoader extends ClassLoader implements BundleClassLoader { 53 54 private BundleImpl bundle; 55 private ZipFile [] classPathJarFiles; private Hashtable nativeLibraries; private Hashtable classCache; private Hashtable resourceURLCache; 60 private ZipFile mainArchive; 62 protected static BundleClassLoader createClassLoader( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibs, NamedPropertySet[] classPath ) throws IOException { 63 if ( isClassLoaderJava2() ) { 64 return new SecureBundleClassLoader( bundle, bundleJarFile, nativeLibs, classPath ); 65 } 66 else { 67 return new SimpleBundleClassLoader( bundle, bundleJarFile, nativeLibs, classPath ); 68 } 69 } 70 71 private static boolean isClassLoaderJava2() { 72 if ( System.getProperty( "com.opensugar.cube.classloader.type", "dynamic" ).equals( "basic" ) ) { 73 return false; 74 } 75 else { 76 return true; 77 } 78 } 79 80 private SimpleBundleClassLoader( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibs, NamedPropertySet[] classPath ) throws IOException { 83 super(); 84 85 initialize( bundle, bundleJarFile, nativeLibs, classPath ); 86 } 87 88 protected SimpleBundleClassLoader( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibs, NamedPropertySet[] classPath, ClassLoader parent ) throws IOException { 91 super( parent ); 92 93 initialize( bundle, bundleJarFile, nativeLibs, classPath ); 94 } 95 96 private void initialize( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibs, NamedPropertySet[] classPath ) throws IOException { 97 this.bundle = bundle; 98 99 mainArchive = new ZipFile ( bundleJarFile ); 100 101 Vector classPathFilesVector = new Vector (); 102 if ( classPath == null || classPath.length == 0 ) { 103 classPathFilesVector.addElement( bundleJarFile ); 105 } 106 else { 107 String classPathItem; 110 ZipEntry entry; 111 File innerJarFileDir; 112 String innerJarFileName; 113 File innerJarFile; 114 int n; 115 for ( int i = 0; i < classPath.length; i++ ) { 116 classPathItem = classPath[ i ].getName().trim(); 117 if ( classPathItem.equals( "." ) ) { 118 classPathFilesVector.addElement( bundleJarFile ); 120 } 121 else { 122 entry = mainArchive.getEntry( classPathItem ); 126 if ( entry != null ) { 127 innerJarFileDir = bundle.getCube().getBundleInnerFilesDirectory( bundle.getBundleId() ); 128 innerJarFileName = classPathItem; 129 n = innerJarFileName.indexOf( '/' ); 130 while ( n > 0 && n < innerJarFileName.length() ) { 131 innerJarFileDir = new File ( innerJarFileDir, innerJarFileName.substring( 0, n ) ); 132 innerJarFileDir.mkdir(); 133 innerJarFileName = innerJarFileName.substring( n + 1 ); 134 n = innerJarFileName.indexOf( '/' ); 135 } 136 innerJarFile = new File ( innerJarFileDir, innerJarFileName ); 137 Util.transferData( mainArchive.getInputStream( entry ), new FileOutputStream ( innerJarFile ) ); 138 classPathFilesVector.addElement( innerJarFile ); 139 } 140 else { 141 } 144 } 145 } 146 } 147 classPathJarFiles = new ZipFile [ classPathFilesVector.size() ]; 148 for ( int i = 0; i < classPathFilesVector.size(); i++ ) { 149 classPathJarFiles[ i ] = new ZipFile ( (File )classPathFilesVector.elementAt( i ) ); 150 } 151 152 nativeLibraries = new Hashtable (); 153 if ( nativeLibs != null ) { 154 String nativeLibName; 155 ZipEntry entry; 156 File innerFileDir; 157 File innerFile; 158 int n; 159 for ( int i = 0; i < nativeLibs.length; i++ ) { 160 nativeLibName = nativeLibs[ i ].getName(); 161 entry = mainArchive.getEntry( nativeLibName ); 162 if ( entry != null ) { 163 innerFileDir = bundle.getCube().getBundleInnerFilesDirectory( bundle.getBundleId() ); 164 n = nativeLibName.indexOf( '/' ); 166 while ( n > 0 && n < nativeLibName.length() ) { 167 innerFileDir = new File ( innerFileDir, nativeLibName.substring( 0, n ) ); 168 innerFileDir.mkdir(); 169 nativeLibName = nativeLibName.substring( n + 1 ); 170 n = nativeLibName.indexOf( '/' ); 171 } 172 innerFile = new File ( innerFileDir, nativeLibName ); 173 Util.transferData( mainArchive.getInputStream( entry ), new FileOutputStream ( innerFile ) ); 174 String nativeLibPath = innerFile.getAbsolutePath(); 175 registerNativeLibrary( nativeLibName, nativeLibPath ); 176 } 177 else { 178 } 181 } 182 } 183 184 classCache = new Hashtable (); 185 resourceURLCache = new Hashtable (); 186 } 187 188 private void registerNativeLibrary( String nativeLibName, String nativeLibPath ) { 189 nativeLibraries.put( nativeLibName, nativeLibPath ); 191 int index = nativeLibName.indexOf( "." ); 193 if ( index != -1 ) { 194 nativeLibraries.put( nativeLibName.substring( 0, index ), nativeLibPath ); 195 } 196 197 index = nativeLibName.lastIndexOf( "/" ); 199 if ( index != -1 ) { 200 nativeLibraries.put( nativeLibName.substring( index + 1 ), nativeLibPath ); 201 } 202 203 if ( nativeLibName.startsWith( "lib" ) && nativeLibName.length() > 3 ) { 205 nativeLibraries.put( nativeLibName.substring( 3 ), nativeLibPath ); 206 } 207 208 String nativeLibraryDir = System.getProperty( "com.opensugar.cube.library.dir", "nativeLibs" ); 210 File dir = new File ( nativeLibraryDir ); 211 if ( !dir.exists() ) { 212 dir.mkdirs(); 213 } 214 try { 215 Util.transferData( new FileInputStream ( new File ( nativeLibPath ) ), new FileOutputStream ( new File ( dir, nativeLibName ) ) ); 216 } 217 catch( IOException e ) { 218 bundle.getCube().log( bundle.getCube().LOG_ERROR, "Cannot create extract native library file from bundle jar to disk", e ); 219 } 220 } 221 222 public String findLibrary( String name ) { 224 return (String )nativeLibraries.get( name ); 225 } 226 227 public Class loadClass( String name ) throws ClassNotFoundException { 228 return loadClass( name, true ); 229 } 230 231 protected Class loadClass( String name, boolean resolve ) throws ClassNotFoundException { 232 name = processClassName( name ); 233 234 Class clazz = null; 235 236 try { 238 if ( isClassLoaderJava2() ) { 239 clazz = getParent().loadClass( name ); 240 } 241 else { 242 clazz = findSystemClass( name ); 243 } 244 } 245 catch( ClassNotFoundException ignore ) {} 246 247 if ( clazz == null ) { 250 int n = name.lastIndexOf( "." ); 251 if ( n != -1 ) { 252 try { 257 clazz = bundle.getCube().getPackageAdmin().loadClass( bundle, name ); 258 } 259 catch ( ClassNotFoundException ignore ) {} 260 } 261 } 262 263 if ( clazz == null ) { 266 clazz = loadOwnClass( name ); 267 } 268 269 return clazz; 270 } 271 272 public URL getResource( String name ) { 273 name = processResourceName( name ); 274 275 URL url = null; 276 277 if ( isClassLoaderJava2() ) { 279 url = getParent().getResource( name ); 280 } 281 else { 282 url = super.getResource( name ); 283 } 284 285 if ( url == null ) { 288 int n = name.lastIndexOf( "/" ); 289 if ( n != -1 ) { 290 url = bundle.getCube().getPackageAdmin().getResource( bundle, name ); 295 } 296 } 297 298 if ( url == null ) { 301 url = getOwnResource( name ); 302 } 303 304 return url; 305 } 306 307 public InputStream getResourceAsStream( String name ) { 308 URL url = getResource( name ); 309 if ( url == null ) { 310 return null; 311 } 312 else { 313 try { 314 if ( url.toString().startsWith( "file://" ) ) { 315 String filename = url.toString(); 316 filename = filename.substring( 7, filename.length() ); 317 return new FileInputStream ( filename ); 318 } 319 return url.openStream(); 320 } 321 catch( IOException e ) { 322 return null; 323 } 324 } 325 } 326 327 private String processClassName( String name ) { 328 return name.replace( '/', '.' ); 331 } 332 333 private String processResourceName( String name ) { 334 if ( name.startsWith( "/" ) && name.length() > 1 ) { 339 name = name.substring( 1, name.length() ); 340 } 341 342 return name; 343 } 344 345 public Class loadOwnClass( String name ) throws ClassNotFoundException { 346 Class clazz = (Class )classCache.get( name ); 347 if ( clazz == null ) { 348 clazz = defineClass( name ); 349 classCache.put( name, clazz ); 350 } 351 return clazz; 352 } 353 354 public URL getOwnResource( String name ) { 355 URL url = (URL )resourceURLCache.get( name ); 356 if ( url == null ) { 357 url = defineResourceURL( name ); 358 if ( url != null ) { 359 resourceURLCache.put( name, url ); 360 } 361 } 362 return url; 363 } 364 365 public void cleanUp() throws IOException { 366 for ( int i = 0; i < classPathJarFiles.length; i++ ) { 367 if ( !classPathJarFiles[ i ].equals( mainArchive ) ) { 368 classPathJarFiles[ i ].close(); 369 } 370 } 371 mainArchive.close(); 372 373 classPathJarFiles = null; 374 } 375 376 public Object getCodeSource() { 377 return null; 378 } 379 380 private Class defineClass( String name ) throws ClassNotFoundException { 381 String classFilePath = name.replace( '.', '/' ) + ".class"; 382 383 byte[] bytes; 384 for ( int i = 0; i < classPathJarFiles.length; i++ ) { 387 try { 388 bytes = getJarEntryContents( classPathJarFiles[ i ], classFilePath ); 389 if ( bytes != null ) { 390 Class clazz = defineClass( name, bytes, 0, bytes.length ); 391 return clazz; 392 } 393 } 394 catch( IOException e ) { 395 bundle.getCube().fireFrameworkEvent( FrameworkEvent.ERROR, bundle, e ); 396 } 397 } 398 throw new ClassNotFoundException ( name ); 399 } 400 401 private URL defineResourceURL( String name ) { 402 for ( int i = 0; i < classPathJarFiles.length; i++ ) { 405 URL url = getJarEntryURL( classPathJarFiles[ i ], name ); 406 if ( url != null ) { 407 return url; 408 } 409 } 410 return null; 411 } 412 413 private static int unjarCount = 0; 415 private static Hashtable unjarred = new Hashtable (); 416 private URL getJarEntryURL( ZipFile archive, String entryName ) { 417 if ( archive.getEntry( entryName ) != null ) { 418 try { 419 422 String key = archive.getName() + "." + entryName; 425 File tmp; 426 if ( unjarred.get( key ) == null ) { 427 tmp = new File ( getUnjarDirectory(), "unjar" + unjarCount++ ); 428 FileOutputStream fos = new FileOutputStream ( tmp ); 429 fos.write( getJarEntryContents( archive, entryName ) ); 430 fos.close(); 431 unjarred.put( key, tmp ); 432 } 433 tmp = (File )unjarred.get( key ); 434 return FileHelper.toURL( tmp ); 435 } 436 catch( MalformedURLException e ) { 437 bundle.getCube().log( bundle.getCube().LOG_ERROR, "Error getting jar entry url", e ); 438 } 439 catch( IOException e ) { 440 bundle.getCube().log( bundle.getCube().LOG_ERROR, "Error getting jar entry url", e ); 441 } 442 } 443 return null; 444 } 445 446 private File unjarDirectory; 447 private synchronized File getUnjarDirectory() { 448 if ( unjarDirectory == null ) { 449 unjarDirectory = bundle.getBundleContext().getDataFile( "temp/unjar" ); 452 if ( unjarDirectory.exists() ) { 453 Util.recursiveFileDelete( unjarDirectory ); 455 } 456 unjarDirectory = bundle.getBundleContext().getDataFile( "temp" ); 459 unjarDirectory.mkdirs(); 460 unjarDirectory = bundle.getBundleContext().getDataFile( "temp/unjar" ); 461 unjarDirectory.mkdirs(); 462 } 463 return unjarDirectory; 464 } 465 466 private byte[] getJarEntryContents( ZipFile archive, String entryName ) throws IOException { 469 ZipEntry entry = archive.getEntry( entryName ); 470 if ( entry != null ) { 471 int entrySize = (int)entry.getSize(); 472 if ( entrySize < 0 ) { 473 throw new IOException ( "Unknown size for " + entry ); 474 } 475 InputStream is = archive.getInputStream( entry ); 476 byte[] bytes = new byte[ entrySize ]; 477 DataInputStream dis = new DataInputStream ( is ); 478 dis.readFully( bytes ); 479 is.close(); 480 return bytes; 481 } 482 return null; 483 } 484 485 } 486 487 | Popular Tags |