blob: 9107c46dc788851cf21a0a67177ea11901ed2872 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.baseadaptor;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Properties;
import org.eclipse.core.runtime.adaptor.LocationManager;
import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile;
import org.eclipse.osgi.baseadaptor.hooks.*;
import org.eclipse.osgi.framework.adaptor.*;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.framework.internal.core.*;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.baseadaptor.*;
import org.eclipse.osgi.service.resolver.PlatformAdmin;
import org.eclipse.osgi.service.resolver.State;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
/**
* A Framework adaptor implementation that allows additional functionality to be
* hooked in. Hooks are configured using {@link HookConfigurator}
* objects. A framework extension may add hook configurators which can be used
* to add hooks to the {@link HookRegistry}.
* @see HookConfigurator
* @see HookRegistry
* @see AdaptorHook
*/
public class BaseAdaptor implements FrameworkAdaptor{
// System property used to set the parent classloader type (boot is the default)
private static final String PROP_PARENT_CLASSLOADER = "osgi.parentClassloader"; //$NON-NLS-1$
// A parent classloader type that specifies the application classloader
private static final String PARENT_CLASSLOADER_APP = "app"; //$NON-NLS-1$
// A parent classloader type that specifies the extension classlaoder
private static final String PARENT_CLASSLOADER_EXT = "ext"; //$NON-NLS-1$
// A parent classloader type that specifies the boot classlaoder
private static final String PARENT_CLASSLOADER_BOOT = "boot"; //$NON-NLS-1$
// A parent classloader type that specifies the framework classlaoder
private static final String PARENT_CLASSLOADER_FWK = "fwk"; //$NON-NLS-1$
// The BundleClassLoader parent to use when creating BundleClassLoaders.
private static ClassLoader bundleClassLoaderParent;
static {
// check property for specified parent
String type = FrameworkProperties.getProperty(BaseAdaptor.PROP_PARENT_CLASSLOADER, BaseAdaptor.PARENT_CLASSLOADER_BOOT);
if (BaseAdaptor.PARENT_CLASSLOADER_FWK.equalsIgnoreCase(type))
bundleClassLoaderParent = FrameworkAdaptor.class.getClassLoader();
else if (BaseAdaptor.PARENT_CLASSLOADER_APP.equalsIgnoreCase(type))
bundleClassLoaderParent = ClassLoader.getSystemClassLoader();
else if (BaseAdaptor.PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) {
ClassLoader appCL = ClassLoader.getSystemClassLoader();
if (appCL != null)
bundleClassLoaderParent = appCL.getParent();
}
// default to boot classloader
if (bundleClassLoaderParent == null)
bundleClassLoaderParent = new ParentClassLoader();
}
// Empty parent classloader. This is used by default as the BundleClassLoader parent.
private static class ParentClassLoader extends ClassLoader {
protected ParentClassLoader() {
super(null);
}
}
private EventPublisher eventPublisher;
private ServiceRegistry serviceRegistry;
private boolean stopping;
private HookRegistry hookRegistry;
private FrameworkLog log;
private BundleContext context;
private BaseStorage storage;
private BundleWatcher bundleWatcher;
/**
* Constructs a BaseAdaptor.
* @param args arguments passed to the adaptor by the framework.
*/
public BaseAdaptor(String[] args) {
if (LocationManager.getConfigurationLocation() == null)
LocationManager.initializeLocations();
hookRegistry = new HookRegistry(this);
FrameworkLogEntry[] errors = hookRegistry.initialize();
if (errors.length > 0)
for (int i = 0; i < errors.length; i++)
getFrameworkLog().log(errors[i]);
storage = getStorage();
// TODO consider passing args to BaseAdaptorHooks
}
/**
* This method will call all configured adaptor hooks {@link AdaptorHook#initialize(BaseAdaptor)} method.
* @see FrameworkAdaptor#initialize(EventPublisher)
*/
public void initialize(EventPublisher publisher) {
this.eventPublisher = publisher;
serviceRegistry = new ServiceRegistryImpl();
((ServiceRegistryImpl) serviceRegistry).initialize();
// set the adaptor for the adaptor hooks
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
adaptorHooks[i].initialize(this);
}
/**
* @see FrameworkAdaptor#initializeStorage()
*/
public void initializeStorage() throws IOException {
storage.initialize(this);
}
/**
* @see FrameworkAdaptor#compactStorage()
*/
public void compactStorage() throws IOException {
storage.compact();
}
/**
* This method will call all the configured adaptor hook {@link AdaptorHook#addProperties(Properties)} methods.
* @see FrameworkAdaptor#getProperties()
*/
public Properties getProperties() {
Properties props = new Properties();
String resource = FrameworkProperties.getProperty(Constants.OSGI_PROPERTIES, Constants.DEFAULT_OSGI_PROPERTIES);
try {
InputStream in = null;
File file = new File(resource);
if (file.exists())
in = new FileInputStream(file);
if (in == null)
in = getClass().getResourceAsStream(resource);
if (in != null) {
try {
props.load(new BufferedInputStream(in));
} finally {
try {
in.close();
} catch (IOException ee) {
// nothing to do
}
}
} else {
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.println("Skipping osgi.properties: " + resource); //$NON-NLS-1$
}
} catch (IOException e) {
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.println("Unable to load osgi.properties: " + e.getMessage()); //$NON-NLS-1$
}
// add the storage properties
storage.addProperties(props);
// add the properties from each adaptor hook
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
adaptorHooks[i].addProperties(props);
return props;
}
/**
* @see FrameworkAdaptor#getInstalledBundles()
*/
public BundleData[] getInstalledBundles() {
return storage.getInstalledBundles();
}
/**
* This method will call each configured adaptor hook {@link AdaptorHook#mapLocationToURLConnection(String)} method
* until one returns a non-null value. If none of the adaptor hooks return a non-null value then the
* string is used to construct a new URL object to open a new url connection.
*
* @see FrameworkAdaptor#mapLocationToURLConnection(String)
*/
public URLConnection mapLocationToURLConnection(String location) throws BundleException {
try {
URLConnection result = null;
// try the adaptor hooks first;
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++) {
result = adaptorHooks[i].mapLocationToURLConnection(location);
if (result != null)
return result;
}
// just do the default
return (new URL(location).openConnection());
} catch (IOException e) {
throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, location), e);
}
}
/**
* @see FrameworkAdaptor#installBundle(String, URLConnection)
*/
public BundleOperation installBundle(String location, URLConnection source) {
return storage.installBundle(location, source);
}
/**
* @see FrameworkAdaptor#updateBundle(BundleData, URLConnection)
*/
public BundleOperation updateBundle(BundleData bundledata, URLConnection source) {
return storage.updateBundle((BaseData) bundledata, source);
}
/**
* @see FrameworkAdaptor#uninstallBundle(BundleData)
*/
public BundleOperation uninstallBundle(BundleData bundledata) {
return storage.uninstallBundle((BaseData) bundledata);
}
/**
* @see FrameworkAdaptor#getTotalFreeSpace()
*/
public long getTotalFreeSpace() throws IOException {
return storage.getFreeSpace();
}
/**
* @see FrameworkAdaptor#getPermissionStorage()
*/
public PermissionStorage getPermissionStorage() throws IOException {
return storage.getPermissionStorage();
}
/**
* @see FrameworkAdaptor#getServiceRegistry()
*/
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
/**
* This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStart(BundleContext)} methods.
* @see FrameworkAdaptor#frameworkStart(BundleContext)
*/
public void frameworkStart(BundleContext fwContext) throws BundleException {
this.context = fwContext;
stopping = false;
BundleResourceHandler.setContext(fwContext);
// always start the storage first
storage.frameworkStart(fwContext);
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
adaptorHooks[i].frameworkStart(fwContext);
}
/**
* This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStop(BundleContext)} methods.
* @see FrameworkAdaptor#frameworkStop(BundleContext)
*/
public void frameworkStop(BundleContext fwContext) throws BundleException {
// first inform all configured adaptor hooks
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
adaptorHooks[i].frameworkStop(fwContext);
// stop the storage last
storage.frameworkStop(fwContext);
fwContext = null;
}
/**
* This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStopping(BundleContext)} methods.
* @see FrameworkAdaptor#frameworkStopping(BundleContext)
*/
public void frameworkStopping(BundleContext fwContext) {
stopping = true;
// always tell storage of stopping first
storage.frameworkStopping(fwContext);
// inform all configured adaptor hooks last
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
adaptorHooks[i].frameworkStopping(fwContext);
}
/**
* @see FrameworkAdaptor#getInitialBundleStartLevel()
*/
public int getInitialBundleStartLevel() {
return storage.getInitialBundleStartLevel();
}
/**
* @see FrameworkAdaptor#setInitialBundleStartLevel(int)
*/
public void setInitialBundleStartLevel(int value) {
storage.setInitialBundleStartLevel(value);
}
/**
* This method calls all configured adaptor hook {@link AdaptorHook#createFrameworkLog()} methods
* until the first one returns a non-null value. If none of the adaptor hooks return a non-null
* value then a framework log implementation which does nothing is returned.
* @see FrameworkAdaptor#getFrameworkLog()
*/
public FrameworkLog getFrameworkLog() {
if (log != null)
return log;
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++) {
log = adaptorHooks[i].createFrameworkLog();
if (log != null)
return log;
}
log = new FrameworkLog() {
public void log(FrameworkEvent frameworkEvent) {
log(new FrameworkLogEntry(frameworkEvent.getBundle().getSymbolicName() == null ? frameworkEvent.getBundle().getLocation() : frameworkEvent.getBundle().getSymbolicName(), FrameworkLogEntry.ERROR, 0, "FrameworkEvent.ERROR", 0, frameworkEvent.getThrowable(), null)); //$NON-NLS-1$
}
public void log(FrameworkLogEntry logEntry) {
System.err.print(logEntry.getEntry() + " "); //$NON-NLS-1$
System.err.println(logEntry.getMessage());
if (logEntry.getThrowable() != null)
logEntry.getThrowable().printStackTrace(System.err);
}
public void setWriter(Writer newWriter, boolean append) {
// do nothing
}
public void setFile(File newFile, boolean append) throws IOException {
// do nothing
}
public File getFile() {
// do nothing
return null;
}
public void setConsoleLog(boolean consoleLog) {
// do nothing
}
public void close() {
// do nothing
}
};
return log;
}
/**
* @see FrameworkAdaptor#createSystemBundleData()
*/
public BundleData createSystemBundleData() throws BundleException {
return new SystemBundleData(this);
}
/**
* @see FrameworkAdaptor#getBundleWatcher()
*/
public BundleWatcher getBundleWatcher() {
if (bundleWatcher != null)
return bundleWatcher;
final BundleWatcher[] watchers = hookRegistry.getWatchers();
if (watchers.length == 0)
return null;
bundleWatcher = new BundleWatcher() {
public void watchBundle(Bundle bundle, int type) {
for (int i = 0; i < watchers.length; i++)
watchers[i].watchBundle(bundle, type);
}
};
return bundleWatcher;
}
/**
* @see FrameworkAdaptor#getPlatformAdmin()
*/
public PlatformAdmin getPlatformAdmin() {
return storage.getStateManager();
}
/**
* @see FrameworkAdaptor#getState()
*/
public State getState() {
return storage.getStateManager().getSystemState();
}
/**
* This method calls all the configured classloading hooks {@link ClassLoadingHook#getBundleClassLoaderParent()} methods
* until one returns a non-null value.
* @see FrameworkAdaptor#getBundleClassLoaderParent()
*/
public ClassLoader getBundleClassLoaderParent() {
// ask the configured adaptor hooks first
ClassLoader result = null;
ClassLoadingHook[] cpManagerHooks = getHookRegistry().getClassLoadingHooks();
for (int i = 0; i < cpManagerHooks.length; i++) {
result = cpManagerHooks[i].getBundleClassLoaderParent();
if (result != null)
return result;
}
// none of the configured adaptor hooks gave use a parent loader; use the default
return bundleClassLoaderParent;
}
/**
* This method calls all the configured adaptor hooks {@link AdaptorHook#handleRuntimeError(Throwable)} methods.
* @see FrameworkAdaptor#handleRuntimeError(Throwable)
*/
public void handleRuntimeError(Throwable error) {
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
adaptorHooks[i].handleRuntimeError(error);
}
/**
* This method calls all the configured adaptor hooks {@link AdaptorHook#matchDNChain(String, String[])} methods
* until one returns a true value.
* @see FrameworkAdaptor#matchDNChain(String, String[])
*/
public boolean matchDNChain(String pattern, String[] dnChain) {
AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
for (int i = 0; i < adaptorHooks.length; i++)
if (adaptorHooks[i].matchDNChain(pattern, dnChain))
return true;
return false;
}
/**
* Returns true if the {@link #frameworkStopping(BundleContext)} method has been called
* @return true if the framework is stopping
*/
public boolean isStopping() {
return stopping;
}
/**
* Returns the event publisher for this BaseAdaptor
* @return the event publisher for this BaseAdaptor
*/
public EventPublisher getEventPublisher() {
return eventPublisher;
}
/**
* Returns the <code>HookRegistry</code> object for this adaptor.
* @return the <code>HookRegistry</code> object for this adaptor.
*/
public HookRegistry getHookRegistry() {
return hookRegistry;
}
/**
* Returns the system bundle's context
* @return the system bundle's context
*/
public BundleContext getContext() {
return context;
}
/**
* Creates a bundle file object for the given content and base data.
* This method must delegate to each configured bundle file factory
* {@link BundleFileFactoryHook#createBundleFile(Object, BaseData, boolean)} method until one
* factory returns a non-null value. If no bundle file factory returns a non-null value
* then the the default behavior will be performed. <p>
* If the specified content is <code>null</code> then the base content of the specified
* bundledata must be found before calling any bundle file factories.
* @param content The object which contains the content of a bundle file. A value of
* <code>null</code> indicates that the storage must find the base content for the
* specified BaseData.
* @param data The BaseData associated with the content
* @return a BundleFile object.
* @throws IOException if an error occured while creating the BundleFile
*/
public BundleFile createBundleFile(Object content, BaseData data) throws IOException {
return storage.createBundleFile(content, data);
}
/**
* Returns true if the persistent storage is read-only
* @return true if the persistent storage is read-only
*/
public boolean isReadOnly() {
return storage.isReadOnly();
}
/*
* This is an experimental method to allow adaptors to replace the storage implementation by
* extending BaseAdaptor and overriding this method. This method is experimental.
* @return a base storage object.
*/
protected BaseStorage getStorage() {
if (storage == null)
storage = BaseStorage.getInstance();
return storage;
}
}