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 import java.security.SecureClassLoader ; 53 import java.security.CodeSource ; 54 55 public class SecureBundleClassLoader extends SecureClassLoader implements BundleClassLoader { 56 57 private BundleImpl bundle; 58 private ZipFile [] classPathJarFiles; private Hashtable nativeLibraries; private Hashtable classCache; private Hashtable resourceURLCache; 63 private ZipFile mainArchive; 65 private CodeSource codeSource; 66 67 protected SecureBundleClassLoader( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibs, NamedPropertySet[] classPath ) throws IOException { 68 super( SecureBundleClassLoader.class.getClassLoader() ); 69 70 if ( bundle.getBundleId() == 0 ) { 71 codeSource = new CodeSource ( new URL ( "file:lib/main.jar" ), null ); 72 } 73 else { 74 try { 75 codeSource = new CodeSource ( new URL ( bundle.getLocation() ), null ); 76 } 77 catch ( MalformedURLException e ) { 78 System.out.println( "Bundle with invalid location: " + bundle.getLocation() ); 79 codeSource = new CodeSource ( new URL ( "file://null" ), null ); 80 } 81 } 82 83 initialize( bundle, bundleJarFile, nativeLibs, classPath ); 84 } 85 86 private static boolean isClassLoaderJava2() { 87 return true; 88 } 89 90 private void initialize( BundleImpl bundle, File bundleJarFile, NamedPropertySet[] nativeLibs, NamedPropertySet[] classPath ) throws IOException { 91 this.bundle = bundle; 92 93 mainArchive = new ZipFile ( bundleJarFile ); 94 95 Vector classPathFilesVector = new Vector (); 96 if ( classPath == null || classPath.length == 0 ) { 97 classPathFilesVector.addElement( bundleJarFile ); 99 } 100 else { 101 String classPathItem; 104 ZipEntry entry; 105 File innerJarFileDir; 106 String innerJarFileName; 107 File innerJarFile; 108 int n; 109 for ( int i = 0; i < classPath.length; i++ ) { 110 classPathItem = classPath[ i ].getName().trim(); 111 if ( classPathItem.equals( "." ) ) { 112 classPathFilesVector.addElement( bundleJarFile ); 114 } 115 else { 116 entry = mainArchive.getEntry( classPathItem ); 120 if ( entry != null ) { 121 innerJarFileDir = bundle.getCube().getBundleInnerFilesDirectory( bundle.getBundleId() ); 122 innerJarFileName = classPathItem; 123 n = innerJarFileName.indexOf( '/' ); 124 while ( n > 0 && n < innerJarFileName.length() ) { 125 innerJarFileDir = new File ( innerJarFileDir, innerJarFileName.substring( 0, n ) ); 126 innerJarFileDir.mkdir(); 127 innerJarFileName = innerJarFileName.substring( n + 1 ); 128 n = innerJarFileName.indexOf( '/' ); 129 } 130 innerJarFile = new File ( innerJarFileDir, innerJarFileName ); 131 Util.transferData( mainArchive.getInputStream( entry ), new FileOutputStream ( innerJarFile ) ); 132 classPathFilesVector.addElement( innerJarFile ); 133 } 134 else { 135 } 138 } 139 } 140 } 141 classPathJarFiles = new ZipFile [ classPathFilesVector.size() ]; 142 for ( int i = 0; i < classPathFilesVector.size(); i++ ) { 143 classPathJarFiles[ i ] = new ZipFile ( (File )classPathFilesVector.elementAt( i ) ); 144 } 145 146 nativeLibraries = new Hashtable (); 147 if ( nativeLibs != null ) { 148 String nativeLibName; 149 ZipEntry entry; 150 File innerFileDir; 151 File innerFile; 152 int n; 153 for ( int i = 0; i < nativeLibs.length; i++ ) { 154 nativeLibName = nativeLibs[ i ].getName(); 155 entry = mainArchive.getEntry( nativeLibName ); 156 if ( entry != null ) { 157 innerFileDir = bundle.getCube().getBundleInnerFilesDirectory( bundle.getBundleId() ); 158 n = nativeLibName.indexOf( '/' ); 160 while ( n > 0 && n < nativeLibName.length() ) { 161 innerFileDir = new File ( innerFileDir, nativeLibName.substring( 0, n ) ); 162 innerFileDir.mkdir(); 163 nativeLibName = nativeLibName.substring( n + 1 ); 164 n = nativeLibName.indexOf( '/' ); 165 } 166 innerFile = new File ( innerFileDir, nativeLibName ); 167 int index = 2; 168 while ( innerFile.exists() ) { 169 innerFile = new File ( innerFileDir, nativeLibName + index ); 170 index++; 171 } 172 Util.transferData( mainArchive.getInputStream( entry ), new FileOutputStream ( innerFile ) ); 173 String nativeLibPath = innerFile.getAbsolutePath(); 174 registerNativeLibrary( nativeLibName, nativeLibPath ); 175 } 176 else { 177 } 180 } 181 } 182 183 classCache = new Hashtable (); 184 resourceURLCache = new Hashtable (); 185 } 186 187 private void registerNativeLibrary( String nativeLibName, String nativeLibPath ) { 188 nativeLibraries.put( nativeLibName, nativeLibPath ); 190 int index = nativeLibName.indexOf( "." ); 192 if ( index != -1 ) { 193 nativeLibraries.put( nativeLibName.substring( 0, index ), nativeLibPath ); 194 } 195 196 index = nativeLibName.lastIndexOf( "/" ); 198 if ( index != -1 ) { 199 nativeLibraries.put( nativeLibName.substring( index + 1 ), nativeLibPath ); 200 } 201 202 if ( nativeLibName.startsWith( "lib" ) && nativeLibName.length() > 3 ) { 204 nativeLibraries.put( nativeLibName.substring( 3 ), nativeLibPath ); 205 } 206 207 String nativeLibraryDir = System.getProperty( "com.opensugar.cube.library.dir", "nativeLibs" ); 209 File dir = new File ( nativeLibraryDir ); 210 if ( !dir.exists() ) { 211 dir.mkdirs(); 212 } 213 try { 214 Util.transferData( new FileInputStream ( new File ( nativeLibPath ) ), new FileOutputStream ( new File ( dir, nativeLibName ) ) ); 215 } 216 catch( IOException e ) { 217 bundle.getCube().log( bundle.getCube().LOG_ERROR, "Cannot create extract native library file from bundle jar to disk", e ); 218 } 219 } 220 221 public String findLibrary( String name ) { 223 return (String )nativeLibraries.get( name ); 224 } 225 226 public Class loadClass( String name ) throws ClassNotFoundException { 227 return loadClass( name, true ); 228 } 229 230 protected Class loadClass( String name, boolean resolve ) throws ClassNotFoundException { 231 name = processClassName( name ); 232 233 Class clazz = null; 234 235 try { 237 if ( isClassLoaderJava2() ) { 238 clazz = getParent().loadClass( name ); 239 } 240 else { 241 clazz = findSystemClass( name ); 242 } 243 } 244 catch( ClassNotFoundException ignore ) {} 245 246 if ( clazz == null ) { 249 int n = name.lastIndexOf( "." ); 250 if ( n != -1 ) { 251 try { 256 clazz = bundle.getCube().getPackageAdmin().loadClass( bundle, name ); 257 } 258 catch ( ClassNotFoundException ignore ) {} 259 } 260 } 261 262 if ( clazz == null ) { 265 clazz = loadOwnClass( name ); 266 } 267 268 return clazz; 269 } 270 271 public URL getResource( String name ) { 272 name = processResourceName( name ); 273 274 URL url = null; 275 276 if ( isClassLoaderJava2() ) { 278 url = getParent().getResource( name ); 279 } 280 else { 281 url = super.getResource( name ); 282 } 283 284 if ( url == null ) { 287 int n = name.lastIndexOf( "/" ); 288 if ( n != -1 ) { 289 url = bundle.getCube().getPackageAdmin().getResource( bundle, name ); 294 } 295 } 296 297 if ( url == null ) { 300 url = getOwnResource( name ); 301 } 302 303 return url; 304 } 305 306 public InputStream getResourceAsStream( String name ) { 307 URL url = getResource( name ); 308 if ( url == null ) { 309 return null; 310 } 311 else { 312 try { 313 if ( url.toString().startsWith( "file://" ) ) { 314 String filename = url.toString(); 315 filename = filename.substring( 7, filename.length() ); 316 return new FileInputStream ( filename ); 317 } 318 return url.openStream(); 319 } 320 catch( IOException e ) { 321 return null; 322 } 323 } 324 } 325 326 private String processClassName( String name ) { 327 return name.replace( '/', '.' ); 330 } 331 332 private String processResourceName( String name ) { 333 if ( name.startsWith( "/" ) && name.length() > 1 ) { 338 name = name.substring( 1, name.length() ); 339 } 340 341 return name; 342 } 343 344 public Class loadOwnClass( String name ) throws ClassNotFoundException { 345 Class clazz = (Class )classCache.get( name ); 346 if ( clazz == null ) { 347 clazz = defineClass( name ); 348 classCache.put( name, clazz ); 349 } 350 return clazz; 351 } 352 353 public URL getOwnResource( String name ) { 354 URL url = (URL )resourceURLCache.get( name ); 355 if ( url == null ) { 356 url = defineResourceURL( name ); 357 if ( url != null ) { 358 resourceURLCache.put( name, url ); 359 } 360 } 361 return url; 362 } 363 364 public void cleanUp() throws IOException { 365 for ( int i = 0; i < classPathJarFiles.length; i++ ) { 366 if ( !classPathJarFiles[ i ].equals( mainArchive ) ) { 367 classPathJarFiles[ i ].close(); 368 } 369 } 370 mainArchive.close(); 371 372 classPathJarFiles = null; 373 } 374 375 public Object getCodeSource() { 376 return codeSource; 377 } 378 379 private Class defineClass( String name ) throws ClassNotFoundException { 380 String classFilePath = name.replace( '.', '/' ) + ".class"; 381 382 byte[] bytes; 383 for ( int i = 0; i < classPathJarFiles.length; i++ ) { 386 try { 387 bytes = getJarEntryContents( classPathJarFiles[ i ], classFilePath ); 388 if ( bytes != null ) { 389 Class clazz = defineClass( name, bytes, 0, bytes.length, codeSource ); 390 return clazz; 391 } 392 } 393 catch( IOException e ) { 394 bundle.getCube().fireFrameworkEvent( FrameworkEvent.ERROR, bundle, e ); 395 } 396 } 397 throw new ClassNotFoundException ( name ); 398 } 399 400 private URL defineResourceURL( String name ) { 401 for ( int i = 0; i < classPathJarFiles.length; i++ ) { 404 URL url = getJarEntryURL( classPathJarFiles[ i ], name ); 405 if ( url != null ) { 406 return url; 407 } 408 } 409 return null; 410 } 411 412 private static int unjarCount = 0; 414 private static Hashtable unjarred = new Hashtable (); 415 private URL getJarEntryURL( ZipFile archive, String entryName ) { 416 if ( archive.getEntry( entryName ) != null ) { 417 try { 418 421 String key = archive.getName() + "." + entryName; 424 File tmp; 425 if ( unjarred.get( key ) == null ) { 426 tmp = new File ( getUnjarDirectory(), "unjar" + unjarCount++ ); 427 FileOutputStream fos = new FileOutputStream ( tmp ); 428 fos.write( getJarEntryContents( archive, entryName ) ); 429 fos.close(); 430 unjarred.put( key, tmp ); 431 } 432 tmp = (File )unjarred.get( key ); 433 return FileHelper.toURL( tmp ); 434 } 435 catch( MalformedURLException e ) { 436 bundle.getCube().log( bundle.getCube().LOG_ERROR, "Error getting jar entry url", e ); 437 } 438 catch( IOException e ) { 439 bundle.getCube().log( bundle.getCube().LOG_ERROR, "Error getting jar entry url", e ); 440 } 441 } 442 return null; 443 } 444 445 private File unjarDirectory; 446 private synchronized File getUnjarDirectory() { 447 if ( unjarDirectory == null ) { 448 unjarDirectory = bundle.getBundleContext().getDataFile( "temp/unjar" ); 451 if ( unjarDirectory.exists() ) { 452 Util.recursiveFileDelete( unjarDirectory ); 454 } 455 unjarDirectory = bundle.getBundleContext().getDataFile( "temp" ); 458 unjarDirectory.mkdirs(); 459 unjarDirectory = bundle.getBundleContext().getDataFile( "temp/unjar" ); 460 unjarDirectory.mkdirs(); 461 } 462 return unjarDirectory; 463 } 464 465 private byte[] getJarEntryContents( ZipFile archive, String entryName ) throws IOException { 468 ZipEntry entry = archive.getEntry( entryName ); 469 if ( entry != null ) { 470 int entrySize = (int)entry.getSize(); 471 if ( entrySize < 0 ) { 472 throw new IOException ( "Unknown size for " + entry ); 473 } 474 InputStream is = archive.getInputStream( entry ); 475 byte[] bytes = new byte[ entrySize ]; 476 DataInputStream dis = new DataInputStream ( is ); 477 dis.readFully( bytes ); 478 is.close(); 479 return bytes; 480 } 481 return null; 482 } 483 484 } 485 486 | Popular Tags |