blob: de99ca0b435033fb0f6f364b5a57293b4d806310 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 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.core.internal.registry;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.eclipse.core.internal.runtime.*;
import org.eclipse.core.runtime.*;
import org.osgi.framework.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* A listener for bundle events. When a bundles come and go we look to see
* if there are any extensions or extension points and update the registry accordingly.
* Using a Synchronous listener here is important. If the
* bundle activator code tries to access the registry to get its extension
* points, we need to ensure that they are in the registry before the
* bundle start is called. By listening sync we are able to ensure that
* happens.
*/
public class EclipseBundleListener implements SynchronousBundleListener {
private static final String PLUGIN_MANIFEST = "plugin.xml"; //$NON-NLS-1$
private static final String FRAGMENT_MANIFEST = "fragment.xml"; //$NON-NLS-1$
private ExtensionRegistry registry;
public EclipseBundleListener(ExtensionRegistry registry) {
this.registry = registry;
}
public void bundleChanged(BundleEvent event) {
/* Only should listen for RESOLVED and UNRESOLVED events.
*
* When a bundle is updated the Framework will publish an UNRESOLVED and
* then a RESOLVED event which should cause the bundle to be removed
* and then added back into the registry.
*
* When a bundle is uninstalled the Framework should publish an UNRESOLVED
* event and then an UNINSTALLED event so the bundle will have been removed
* by the UNRESOLVED event before the UNINSTALLED event is published.
*
* When a bundle is refreshed from PackageAdmin an UNRESOLVED event will be
* published which will remove the bundle from the registry. If the bundle
* can be RESOLVED after a refresh then a RESOLVED event will be published
* which will add the bundle back. This is required because the classloader
* will have been refreshed for the bundle so all extensions and extension
* points for the bundle must be refreshed.
*/
Bundle bundle = event.getBundle();
switch (event.getType()) {
case BundleEvent.RESOLVED :
addBundle(bundle);
break;
case BundleEvent.UNRESOLVED :
removeBundle(bundle);
break;
}
}
public void processBundles(Bundle[] bundles) {
for (int i = 0; i < bundles.length; i++) {
if (isBundleResolved(bundles[i]))
addBundle(bundles[i]);
else
removeBundle(bundles[i]);
}
}
private boolean isBundleResolved(Bundle bundle) {
return (bundle.getState() & (Bundle.RESOLVED | Bundle.ACTIVE | Bundle.STARTING | Bundle.STOPPING)) != 0;
}
private void removeBundle(Bundle bundle) {
registry.remove(bundle.getSymbolicName(), bundle.getBundleId());
}
private void addBundle(Bundle bundle) {
// if the given bundle already exists in the registry then return.
// note that this does not work for update cases.
if (registry.getNamespace(bundle.getSymbolicName()) != null)
return;
Namespace bundleModel = getBundleModel(bundle);
if (bundleModel == null)
return;
// Do not synchronize on registry here because the registry handles
// the synchronization for us in registry.add
registry.add(bundleModel);
}
/**
* Tries to create a bundle model from a plugin/fragment manifest in the
* bundle.
*/
private Namespace getBundleModel(Bundle bundle) {
// bail out if system bundle
if (bundle.getBundleId() == 0)
return null;
// bail out if the bundle does not have a symbolic name
if (bundle.getSymbolicName() == null)
return null;
InputStream is = null;
String manifestType = null;
boolean isFragment = InternalPlatform.getDefault().isFragment(bundle);
String manifestName = isFragment ? FRAGMENT_MANIFEST : PLUGIN_MANIFEST;
try {
URL url = bundle.getEntry(manifestName);
if (url != null) {
is = url.openStream();
manifestType = isFragment ? ExtensionsParser.FRAGMENT : ExtensionsParser.PLUGIN;
}
} catch (IOException ex) {
is = null;
}
if (is == null)
return null;
try {
String message = Policy.bind("parse.problems", bundle.getLocation()); //$NON-NLS-1$
MultiStatus problems = new MultiStatus(Platform.PI_RUNTIME, ExtensionsParser.PARSE_PROBLEM, message, null); //$NON-NLS-1$
ResourceBundle b = null;
try {
b = ResourceTranslator.getResourceBundle(bundle);
} catch (MissingResourceException e) {
//Ignore the exception
}
Namespace bundleModel = new ExtensionsParser(problems).parseManifest(new InputSource(is), manifestType, manifestName, b);
bundleModel.setUniqueIdentifier(bundle.getSymbolicName());
bundleModel.setBundle(bundle);
if (isFragment) {
Bundle[] hosts = InternalPlatform.getDefault().getHosts(bundle);
if (hosts != null && hosts.length > 0)
bundleModel.setHostIdentifier(hosts[0].getSymbolicName());
}
if (problems.getSeverity() != IStatus.OK)
InternalPlatform.getDefault().log(problems);
return bundleModel;
} catch (SAXException e) {
// TODO: need to log this
e.printStackTrace();
return null;
} catch (IOException e) {
// TODO: need to log this
e.printStackTrace();
return null;
} finally {
try {
is.close();
} catch (IOException ioe) {
// nothing to do
}
}
}
}