package org.pentaho.platform.osgi; import org.apache.commons.lang.StringUtils; import org.jboss.modules.Module; import org.jboss.modules.ModuleClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** * Created by nbaker on 2/4/15. */ public class SystemPackageExtrapolator { public static final String ORG_OSGI_FRAMEWORK_SYSTEM_PACKAGES_EXTRA = "org.osgi.framework.system.packages.extra"; Logger logger = LoggerFactory.getLogger( getClass() ); private List<PackageProvider> providers = new ArrayList<>(); public SystemPackageExtrapolator() { providers.add( new JBossModulePackageProvider() ); providers.add( new UrlClassLoaderPackageProvider() ); } public SystemPackageExtrapolator( List<PackageProvider> providers ) { this.providers = providers; } interface PackageProvider { Set<String> getPackages(); } static class JBossModulePackageProvider implements PackageProvider { private Module module; @Override public Set<String> getPackages() { Set<String> exportedPaths = null; if ( module == null ) { // assume we're in the module ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // String comparison as we may not have the JBoss Modules classes. if ( classLoader.getClass().getName().equals( "org.jboss.modules.ModuleClassLoader" ) ) { exportedPaths = ( (ModuleClassLoader) classLoader ).getModule().getExportedPaths(); } } else { exportedPaths = module.getExportedPaths(); } Set<String> packages = new HashSet<String>(); if ( exportedPaths != null ) { for ( String exportedPath : exportedPaths ) { packages.add( exportedPath.replaceAll( "/", "." ) ); } } return packages; } public void setModule( Module module ) { this.module = module; } } class UrlClassLoaderPackageProvider implements PackageProvider { @Override public Set<String> getPackages() { Set<String> packages = new HashSet<String>(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); do { if ( !URLClassLoader.class.isAssignableFrom( classLoader.getClass() ) ) { continue; } URL[] urLs = ( (URLClassLoader) classLoader ).getURLs(); for ( URL url : urLs ) { try { String fileName = URLDecoder.decode( url.getFile() ); File file = new File( fileName ); if ( !file.exists() || file.isDirectory() ) { continue; } JarFile jarFile = new JarFile( file ); Enumeration<JarEntry> entries = jarFile.entries(); while ( entries.hasMoreElements() ) { packages.add( getPackageName( entries.nextElement() ) ); } } catch ( IOException e ) { logger.debug( "Error procesing jar for packages", e ); } } } while ( ( classLoader = classLoader.getParent() ) != null ); return packages; } } static String getPackageName( JarEntry jarEntry ) { String name = jarEntry.getName(); int lastSlash = name.lastIndexOf( '/' ); if ( lastSlash >= 0 ) { return name.substring( 0, lastSlash ).replaceAll( "\\/", "." ); } return ""; } public Properties expandProperties( Properties properties ) { Set<String> packages = new HashSet<String>(); for ( PackageProvider provider : providers ) { packages.addAll( provider.getPackages() ); } String packagesImports = properties.getProperty( ORG_OSGI_FRAMEWORK_SYSTEM_PACKAGES_EXTRA ); String[] split = packagesImports.split( "," ); String[] expanded = expandPackages( split, packages.toArray( new String[packages.size()] ) ); properties.setProperty( ORG_OSGI_FRAMEWORK_SYSTEM_PACKAGES_EXTRA, StringUtils.join( expanded, "," ) ); return properties; } private String[] expandPackages( String[] packages, String[] availablePackages ) { Set<String> qualifiedPackages = new HashSet<String>(); Set<String> qualifiedPackagesWhole = new HashSet<String>(); Set<String> imports = new HashSet<String>(); for ( String pack : packages ) { pack = pack.trim(); if ( pack.indexOf( ";" ) > 0 && pack.indexOf( "*" ) == -1 ) { qualifiedPackages.add( pack.substring( 0, pack.indexOf( ";" ) ) ); qualifiedPackagesWhole.add( pack ); } } for ( String pack : packages ) { if ( StringUtils.isNotEmpty( pack ) && pack.contains( ".*" ) ) { // expand out String basePackage = pack.substring( 0, pack.indexOf( "*" ) ).trim(); // including "." String predicate = pack.substring( pack.indexOf( "*" ) + 1 ); for ( String aPackage : availablePackages ) { if ( aPackage.startsWith( basePackage ) && !qualifiedPackages.contains( aPackage ) ) { imports.add( aPackage + predicate ); } } imports.add( basePackage.substring( 0, basePackage.length() - 1 ) + predicate ); } else { imports.add( pack ); } } imports.addAll( qualifiedPackagesWhole ); return imports.toArray( new String[ imports.size() ] ); } }