All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ops4j.pax.web.utils.ClassPathUtil Maven / Gradle / Ivy

/*
 * Copyright 2012 Achim Nierbeck.
 *
 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 * you may not use  this file  except in  compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed  under the  License is distributed on an "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 * implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package org.ops4j.pax.web.utils;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.packageadmin.RequiredBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author achim
 *
 */
public class ClassPathUtil {
	
	/**
     * Logger.
     */
    private static final Logger LOG = LoggerFactory.getLogger( ClassPathUtil.class );

	/**
	 * Returns a list of urls to jars that composes the Bundle-ClassPath.
	 *
	 * @param bundle the bundle from which the class path should be taken
	 *
	 * @return list or urls to jars that composes the Bundle-ClassPath.
	 */
	public static URL[] getClassPathJars( final Bundle bundle )
	{
	    final List urls = new ArrayList();
	    final String bundleClasspath = (String) bundle.getHeaders().get( "Bundle-ClassPath" );
	    if( bundleClasspath != null )
	    {
	        String[] segments = bundleClasspath.split( "," );
	        for( String segment : segments )
	        {
	            final URL url = bundle.getEntry( segment );
	            if( url != null )
	            {
	                if( url.toExternalForm().endsWith( "jar" ) )
	                {
	                    LOG.debug( "Using url: " + url );
	                    try
	                    {
	                        URL jarUrl = new URL( "jar:" + url.toExternalForm() + "!/" );
	                        urls.add( jarUrl );
	                    }
	                    catch( MalformedURLException ignore )
	                    {
	                        LOG.debug( ignore.getMessage() );
	                    }
	                }
	            }
	        }
	    }
	    LOG.debug( "Bundle-ClassPath URLs: " + urls );
	    //adds the depending bundles to the "classloader" space
	    urls.addAll(getLocationsOfBundlesInClassSpace(bundle));
	    return urls.toArray( new URL[urls.size()] );
	}

	/**
	 * Gets the locations of the bundles in the Class Space. Beware, in Karaf this will return the URL with which the bundle
	 * was originally provisioned, i.e. could potentially return wrap:..., mvn:..., etc. and even include URL parameters (i.e. ?Webapp-Context=...).
	 * 
	 * @param bundle the bundle for which to perform the lookup
	 * 
	 * @return	list of locations of bundles in class space
	 * 	
	 */
	
	private static List getLocationsOfBundlesInClassSpace(Bundle bundle) {
		List urls = new ArrayList();
		Set importedBundles = getBundlesInClassSpace(bundle, new HashSet());
		for (Bundle importedBundle : importedBundles) {
			URL url = getLocationOfBundle(importedBundle);
	        if (url != null) {
	        	urls.add(url);
	        }
		}
	    return urls;
	}

	private static URL getLocationOfBundle(Bundle importedBundle) {
		URL url = null;
		try {
			url = new URL(importedBundle.getLocation()); 
		} catch (MalformedURLException e) {
			try {
			url = importedBundle.getEntry("/");
			} catch (Exception e2) {
				LOG.warn("Exception while calculating location of bundle", e);
			}
		}
		return url;
	}

	/**
	 * Gets a list of bundles that are imported or required by this bundle.
	 * 
	 * @param 	bundle the bundle for which to perform the lookup
	 * 
	 * @return	list of imported and required bundles
	 * 	
	 */
	public static Set getBundlesInClassSpace(Bundle bundle, Set bundleSet) {
		Set bundles = new HashSet(); 
		if (bundle == null) {
			LOG.error("Incoming bundle is null");
			return bundles; 
		}
		if (bundle.getBundleContext() == null) {
			LOG.error("Bundle context == null This isn't supposed to happen");
			return bundles;
		}
		
		// Get package admin service.
	    ServiceReference ref = bundle.getBundleContext().getServiceReference(PackageAdmin.class.getName());
	    if (ref == null) {
	        LOG.error("PackageAdmin service is unavailable.");
	        return bundles;
	    }
	    try {
	        PackageAdmin pa = (PackageAdmin) bundle.getBundleContext().getService(ref);
	        if (pa == null) {
	            LOG.error("PackageAdmin service is unavailable.");
	            return bundles;
	        }
	        
	        Dictionary headers = bundle.getHeaders();
	        String importPackage = (String) headers.get("Import-Package");
	        String requiredBundleHeader = (String) headers.get("Require-Bundle");
	        
	        // Process the Import-Package header
	        if (importPackage != null) {
	            String[] importPackages = importPackage.split(",");
	            for (String impPackage : importPackages) {
	            	String[] split = impPackage.split(";");
	            	String name = split[0].trim();
	            	if (name.matches("^[0-9].*"))
	            		continue; //we split into a version range jump over it. 
					ExportedPackage[] exportedPackages = pa.getExportedPackages(name);
	            	if (exportedPackages != null) {
		            	for (ExportedPackage exportedPackage : exportedPackages) {
							if (Arrays.asList(exportedPackage.getImportingBundles()).contains(bundle)) {
								Bundle exportingBundle = exportedPackage.getExportingBundle();
								//skip System-Bundle
								if (exportingBundle.getBundleId() == 0)
									continue;
								if (!bundles.contains(exportingBundle))
									bundles.add(exportingBundle);
							}
						}
	            	}
				}
	        }
	        
	        // Process the Require-Bundle header 
	        if (requiredBundleHeader != null) {
	        	String[] reqBundles = requiredBundleHeader.split(",");
	            for (String reqBundle : reqBundles) {
	            	String[] split = reqBundle.split(";");
	            	String name = split[0].trim();
	            	if (name.matches("^[0-9].*"))
	            		continue; //we split into a version range jump over it. 
					RequiredBundle[] requiredBundles = pa.getRequiredBundles(name);
					if (requiredBundles != null) {
		            	for (RequiredBundle requiredBundle : requiredBundles) {
							if (Arrays.asList(requiredBundle.getRequiringBundles()).contains(bundle)) {
								if (requiredBundle.getBundle().getBundleId() == 0)
									continue;
								bundles.add(requiredBundle.getBundle());
							}
						}
	            	}
				}
	        }
	        
	    }
	    finally {
	    	if (bundle != null && bundle.getBundleContext() != null)
	    		bundle.getBundleContext().ungetService(ref);
	    }
	    Set transitiveBundles = new HashSet();
	    
	    if (!bundleSet.containsAll(bundles)) {
	    	bundles.removeAll(bundleSet);
	    	bundleSet.addAll(bundles);
	    	for (Bundle importedBundle : bundles) {
	    		transitiveBundles.addAll(getBundlesInClassSpace(importedBundle, bundleSet));
	    	}
	    }
	    return bundleSet;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy