| /******************************************************************************* |
| * Copyright (c) 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.framework.internal.core; |
| |
| import java.io.IOException; |
| import java.net.URL; |
| import java.security.PermissionCollection; |
| import java.security.ProtectionDomain; |
| import org.eclipse.osgi.framework.adaptor.BundleData; |
| import org.eclipse.osgi.framework.debug.Debug; |
| import org.osgi.framework.*; |
| |
| public class BundleFragment extends AbstractBundle { |
| |
| /** The resolved host that this fragment is attached to */ |
| protected BundleHost host; |
| |
| /** |
| * @param bundledata |
| * @param framework |
| * @throws BundleException |
| */ |
| public BundleFragment(BundleData bundledata, Framework framework) throws BundleException { |
| super(bundledata, framework); |
| host = null; |
| } |
| |
| /** |
| * Load the bundle. |
| * @exception org.osgi.framework.BundleException |
| */ |
| protected void load() throws BundleException { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| if ((state & (INSTALLED)) == 0) { |
| Debug.println("Bundle.load called when state != INSTALLED: " + this); //$NON-NLS-1$ |
| Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$ |
| } |
| } |
| |
| if (framework.isActive()) { |
| SecurityManager sm = System.getSecurityManager(); |
| |
| if (sm != null) { |
| PermissionCollection collection = framework.permissionAdmin.createPermissionCollection(this); |
| |
| domain = new ProtectionDomain(null, collection); |
| } |
| |
| try { |
| bundledata.open(); /* make sure the BundleData is open */ |
| } catch (IOException e) { |
| throw new BundleException(Msg.formatter.getString("BUNDLE_READ_EXCEPTION"), e); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| /** |
| * Changes the state from ACTIVE | RESOVED to INSTALLED. This is called when a |
| * host gets reloaded or unloaded. |
| * This method must be called while holding the bundles lock. |
| * |
| * @return true if an exported package is "in use". i.e. it has been imported by a bundle |
| */ |
| protected boolean unresolve() { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| if ((state & (INSTALLED | RESOLVED)) == 0) { |
| Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: " + this); //$NON-NLS-1$ |
| Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$ |
| } |
| } |
| |
| if (framework.isActive()) { |
| if (host != null) { |
| if (state == RESOLVED) { |
| state = INSTALLED; |
| // publish UNRESOLVED event here. |
| framework.publishBundleEvent(BundleEvent.UNRESOLVED, this); |
| host = null; |
| } |
| } |
| } else { |
| /* close the outgoing jarfile */ |
| try { |
| this.bundledata.close(); |
| } catch (IOException e) { |
| // Do Nothing |
| } |
| } |
| |
| return (false); |
| } |
| |
| /** |
| * Reload from a new bundle. |
| * This method must be called while holding the bundles lock. |
| * |
| * @param newBundle Dummy Bundle which contains new data. |
| * @return true if an exported package is "in use". i.e. it has been imported by a bundle |
| * @exception org.osgi.framework.BundleException |
| */ |
| protected boolean reload(AbstractBundle newBundle) throws BundleException { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| if ((state & (INSTALLED | RESOLVED)) == 0) { |
| Debug.println("Bundle.reload called when state != INSTALLED | RESOLVED: " + this); //$NON-NLS-1$ |
| Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$ |
| } |
| } |
| |
| boolean exporting = false; |
| |
| if (framework.isActive()) { |
| if (host != null) { |
| if (state == RESOLVED) { |
| // Unresolving the host will cause the fragment to unresolve |
| exporting = host.unresolve(); |
| } |
| } |
| |
| } |
| |
| if (!exporting) { |
| /* close the outgoing jarfile */ |
| try { |
| this.bundledata.close(); |
| } catch (IOException e) { |
| // Do Nothing |
| } |
| } |
| |
| this.bundledata = newBundle.bundledata; |
| this.bundledata.setBundle(this); |
| return (exporting); |
| } |
| |
| /** |
| * Refresh the bundle. This is called by Framework.refreshPackages. |
| * This method must be called while holding the bundles lock. |
| * this.loader.unimportPackages must have already been called before calling |
| * this method! |
| * |
| * @exception org.osgi.framework.BundleException if an exported package is "in use". i.e. it has been imported by a bundle |
| */ |
| protected void refresh() throws BundleException { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0) { |
| Debug.println("Bundle.refresh called when state != UNINSTALLED | INSTALLED | RESOLVED: " + this); //$NON-NLS-1$ |
| Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$ |
| } |
| } |
| |
| if (state == RESOLVED) { |
| host = null; |
| state = INSTALLED; |
| // Do not publish UNRESOLVED event here. This is done by caller |
| // to resolve if appropriate. |
| } |
| manifestLocalization = null; |
| } |
| |
| /** |
| * Unload the bundle. |
| * This method must be called while holding the bundles lock. |
| * |
| * @return true if an exported package is "in use". i.e. it has been imported by a bundle |
| */ |
| protected boolean unload() { |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| if ((state & (UNINSTALLED | INSTALLED | RESOLVED)) == 0) { |
| Debug.println("Bundle.unload called when state != UNINSTALLED | INSTALLED | RESOLVED: " + this); //$NON-NLS-1$ |
| Debug.printStackTrace(new Exception("Stack trace")); //$NON-NLS-1$ |
| } |
| } |
| |
| boolean exporting = false; |
| |
| if (framework.isActive()) { |
| if (host != null) { |
| BundleHost resumeHost = host; |
| if (state == RESOLVED) { |
| // Unresolving the host will cause the fragment to unresolve |
| try { |
| exporting = host.unresolve(); |
| } catch (BundleException be) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, be); |
| } |
| } |
| if (!exporting) { |
| domain = null; |
| try { |
| this.bundledata.close(); |
| } catch (IOException e) { // Do Nothing. |
| } |
| } |
| // We must resume the host now that we are unloaded. |
| framework.resumeBundle(resumeHost); |
| } |
| } else { |
| try { |
| this.bundledata.close(); |
| } catch (IOException e) { // Do Nothing. |
| } |
| } |
| |
| return (exporting); |
| } |
| |
| /** |
| * This method loads a class from the bundle. |
| * |
| * @param name the name of the desired Class. |
| * @param checkPermission indicates whether a permission check should be done. |
| * @return the resulting Class |
| * @exception java.lang.ClassNotFoundException if the class definition was not found. |
| */ |
| protected Class loadClass(String name, boolean checkPermission) throws ClassNotFoundException { |
| if (checkPermission) { |
| framework.checkAdminPermission(); |
| checkValid(); |
| } |
| // cannot load a class from a fragment because there is no classloader |
| // associated with fragments. |
| throw new ClassNotFoundException(Msg.formatter.getString("BUNDLE_FRAGMENT_CNFE", name)); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Find the specified resource in this bundle. |
| * |
| * This bundle's class loader is called to search for the named resource. |
| * If this bundle's state is <tt>INSTALLED</tt>, then only this bundle will |
| * be searched for the specified resource. Imported packages cannot be searched |
| * when a bundle has not been resolved. |
| * |
| * @param name The name of the resource. |
| * See <tt>java.lang.ClassLoader.getResource</tt> for a description of |
| * the format of a resource name. |
| * @return a URL to the named resource, or <tt>null</tt> if the resource could |
| * not be found or if the caller does not have |
| * the <tt>AdminPermission</tt>, and the Java Runtime Environment supports permissions. |
| * |
| * @exception java.lang.IllegalStateException If this bundle has been uninstalled. |
| */ |
| public URL getResource(String name) { |
| checkValid(); |
| // cannot get a resource for a fragment because there is no classloader |
| // associated with fragments. |
| return (null); |
| |
| } |
| |
| /** |
| * Internal worker to start a bundle. |
| * |
| * @param persistent if true persistently record the bundle was started. |
| */ |
| protected void startWorker(boolean persistent) throws BundleException { |
| if (framework.active) { |
| if ((state & (STARTING | ACTIVE)) != 0) { |
| return; |
| } |
| |
| if (state == INSTALLED) { |
| framework.packageAdmin.resolveBundles(); |
| |
| if (state != RESOLVED) { |
| throw new BundleException(getResolutionFailureMessage()); |
| } |
| } |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| Debug.println("Bundle: Active sl = " + framework.startLevelManager.getStartLevel() + "; Bundle " + getBundleId() + " sl = " + getStartLevel()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| if (getStartLevel() <= framework.startLevelManager.getStartLevel()) { |
| if (state == UNINSTALLED) { |
| throw new BundleException(Msg.formatter.getString("BUNDLE_UNINSTALLED_EXCEPTION")); //$NON-NLS-1$ |
| } |
| if (framework.active) { |
| state = ACTIVE; |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| Debug.println("->started " + this); //$NON-NLS-1$ |
| } |
| |
| framework.publishBundleEvent(BundleEvent.STARTED, this); |
| } |
| } |
| } |
| |
| if (persistent) { |
| setStatus(Constants.BUNDLE_STARTED, true); |
| } |
| } |
| |
| /** |
| * Internal worker to stop a bundle. |
| * |
| * @param persistent if true persistently record the bundle was stopped. |
| */ |
| protected void stopWorker(boolean persistent) throws BundleException { |
| if (persistent) { |
| setStatus(Constants.BUNDLE_STARTED, false); |
| } |
| |
| if (framework.active) { |
| if ((state & (STOPPING | RESOLVED | INSTALLED)) != 0) { |
| return; |
| } |
| |
| state = RESOLVED; |
| |
| if (Debug.DEBUG && Debug.DEBUG_GENERAL) { |
| Debug.println("->stopped " + this); //$NON-NLS-1$ |
| } |
| |
| framework.publishBundleEvent(BundleEvent.STOPPED, this); |
| } |
| } |
| |
| /** |
| * Provides a list of {@link ServiceReference}s for the services |
| * registered by this bundle |
| * or <code>null</code> if the bundle has no registered |
| * services. |
| * |
| * <p>The list is valid at the time |
| * of the call to this method, but the framework is a very dynamic |
| * environment and services can be modified or unregistered at anytime. |
| * |
| * @return An array of {@link ServiceReference} or <code>null</code>. |
| * @exception java.lang.IllegalStateException If the |
| * bundle has been uninstalled. |
| * @see ServiceRegistrationImpl |
| * @see ServiceReference |
| */ |
| public ServiceReference[] getRegisteredServices() { |
| checkValid(); |
| // Fragments cannot have a BundleContext and therefore |
| // cannot have any services registered. |
| return null; |
| } |
| |
| /** |
| * Provides a list of {@link ServiceReference}s for the |
| * services this bundle is using, |
| * or <code>null</code> if the bundle is not using any services. |
| * A bundle is considered to be using a service if the bundle's |
| * use count for the service is greater than zero. |
| * |
| * <p>The list is valid at the time |
| * of the call to this method, but the framework is a very dynamic |
| * environment and services can be modified or unregistered at anytime. |
| * |
| * @return An array of {@link ServiceReference} or <code>null</code>. |
| * @exception java.lang.IllegalStateException If the |
| * bundle has been uninstalled. |
| * @see ServiceReference |
| */ |
| public ServiceReference[] getServicesInUse() { |
| checkValid(); |
| // Fragments cannot have a BundleContext and therefore |
| // cannot have any services in use. |
| return null; |
| } |
| |
| public org.osgi.framework.Bundle getHost() { |
| return host; |
| } |
| |
| public boolean isFragment() { |
| return true; |
| } |
| |
| /** |
| * Sets the host for this fragment from the list of available |
| * BundleExporters. If a matching host cannot be found then a |
| * resolve Exception is logged. |
| * @param value the BundleHost to set the host to |
| */ |
| protected boolean setHost(BundleHost value) { |
| host = value; |
| if (host != null) { |
| try { |
| host.attachFragment(this); |
| } catch (BundleException be) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, host, be); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public BundleLoader getBundleLoader() { |
| // Fragments cannot have a BundleLoader. |
| return null; |
| } |
| |
| /** |
| * Return the current context for this bundle. |
| * |
| * @return BundleContext for this bundle. |
| */ |
| protected BundleContextImpl getContext() { |
| // Fragments cannot have a BundleContext. |
| return null; |
| } |
| } |