package org.eclipse.core.internal.registry.osgi;
import java.io.*;
import java.net.URL;
import java.util.*;
import org.eclipse.core.internal.registry.ExtensionRegistry;
import org.eclipse.core.internal.registry.RegistryMessages;
import org.eclipse.core.internal.runtime.ResourceTranslator;
import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
public class EclipseBundleListener implements SynchronousBundleListener {
private static final String PLUGIN_MANIFEST = "plugin.xml";
private static final String FRAGMENT_MANIFEST = "fragment.xml";
private final ExtensionRegistry registry;
private final RegistryStrategyOSGI strategy;
private final Object token;
private final HashMap<String, Long> dynamicAddStateStamps = new HashMap<>();
private final long currentStateStamp[] = new long[] {0};
public EclipseBundleListener(ExtensionRegistry registry, Object key, RegistryStrategyOSGI strategy) {
this.registry = registry;
this.token = key;
this.strategy = strategy;
}
@Override
public void bundleChanged(BundleEvent event) {
Bundle bundle = event.getBundle();
switch (event.getType()) {
case BundleEvent.RESOLVED :
synchronized (currentStateStamp) {
long newStateStamp = registry.computeState();
if (currentStateStamp[0] != newStateStamp) {
currentStateStamp[0] = newStateStamp;
dynamicAddStateStamps.clear();
}
}
addBundle(bundle, true);
break;
case BundleEvent.UNRESOLVED :
removeBundle(bundle);
break;
}
}
public void processBundles(Bundle[] bundles) {
for (Bundle bundle : bundles) {
if (isBundleResolved(bundle)) {
addBundle(bundle, false);
} else {
removeBundle(bundle);
}
}
}
private boolean isBundleResolved(Bundle bundle) {
return (bundle.getState() & (Bundle.RESOLVED | Bundle.ACTIVE | Bundle.STARTING | Bundle.STOPPING)) != 0;
}
private void removeBundle(Bundle bundle) {
long timestamp = 0;
if (strategy.checkContributionsTimestamp()) {
URL pluginManifest = getExtensionURL(bundle, false);
if (pluginManifest != null)
timestamp = strategy.getExtendedTimestamp(bundle, pluginManifest);
}
registry.remove(Long.toString(bundle.getBundleId()), timestamp);
}
static public URL getExtensionURL(Bundle bundle, boolean report) {
if (bundle.getSymbolicName() == null)
return null;
boolean isFragment = OSGIUtils.getDefault().isFragment(bundle);
String manifestName = isFragment ? FRAGMENT_MANIFEST : PLUGIN_MANIFEST;
URL extensionURL = bundle.getEntry(manifestName);
if (extensionURL == null)
return null;
if (!isSingleton(bundle)) {
if (report && !isGeneratedManifest(bundle)) {
String message = NLS.bind(RegistryMessages.parse_nonSingleton, bundle.getSymbolicName());
RuntimeLog.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, message, null));
}
return null;
}
if (!isFragment)
return extensionURL;
Bundle[] hosts = OSGIUtils.getDefault().getHosts(bundle);
if (hosts == null)
return null;
if (isSingleton(hosts[0]))
return extensionURL;
if (report) {
String message = NLS.bind(RegistryMessages.parse_nonSingletonFragment, bundle.getSymbolicName(), hosts[0].getSymbolicName());
RuntimeLog.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, message, null));
}
return null;
}
private static boolean isGeneratedManifest(Bundle bundle) {
return bundle.getHeaders("").get("Generated-from") != null;
}
private void addBundle(Bundle bundle, boolean checkNLSFragments) {
if (checkNLSFragments)
checkForNLSFragment(bundle);
IContributor contributor = ContributorFactoryOSGi.createContributor(bundle);
if (registry.hasContributor(contributor))
return;
URL pluginManifest = getExtensionURL(bundle, true);
if (pluginManifest == null)
return;
InputStream is;
try {
is = new BufferedInputStream(pluginManifest.openStream());
} catch (IOException ex) {
is = null;
}
if (is == null)
return;
ResourceBundle translationBundle = null;
try {
translationBundle = ResourceTranslator.getResourceBundle(bundle);
} catch (MissingResourceException e) {
}
long timestamp = 0;
if (strategy.checkContributionsTimestamp())
timestamp = strategy.getExtendedTimestamp(bundle, pluginManifest);
registry.addContribution(is, contributor, true, pluginManifest.getPath(), translationBundle, token, timestamp);
}
private void checkForNLSFragment(Bundle bundle) {
if (!OSGIUtils.getDefault().isFragment(bundle)) {
synchronized (currentStateStamp) {
dynamicAddStateStamps.put(Long.toString(bundle.getBundleId()), Long.valueOf(currentStateStamp[0]));
}
return;
}
Bundle[] hosts = OSGIUtils.getDefault().getHosts(bundle);
if (hosts == null)
return;
for (Bundle host : hosts) {
checkForNLSFiles(host, bundle);
}
}
private void checkForNLSFiles(Bundle host, Bundle fragment) {
String hostID = Long.toString(host.getBundleId());
synchronized (currentStateStamp) {
Long hostStateStamp = dynamicAddStateStamps.get(hostID);
if (hostStateStamp != null && currentStateStamp[0] == hostStateStamp.longValue())
return;
}
Bundle[] fragments = OSGIUtils.getDefault().getFragments(host);
boolean refresh = false;
if (hasNLSFilesFor(host, fragment)) {
refresh = true;
} else {
for (int i = 0; i < fragments.length && !refresh; i++) {
if (fragment.equals(fragments[i]))
continue;
if (hasNLSFilesFor(fragments[i], fragment)) {
refresh = true;
}
}
}
if (refresh) {
removeBundle(host);
addBundle(host, false);
for (Bundle b : fragments) {
if (fragment.equals(b)) {
continue;
}
removeBundle(b);
addBundle(b, false);
}
synchronized (currentStateStamp) {
dynamicAddStateStamps.put(hostID, Long.valueOf(currentStateStamp[0]));
}
}
}
private boolean hasNLSFilesFor(Bundle target, Bundle fragment) {
if (!registry.hasContributor(Long.toString(target.getBundleId())))
return false;
Dictionary<?, ?> targetHeaders = target.getHeaders("");
String localization = (String) targetHeaders.get(Constants.BUNDLE_LOCALIZATION);
if (localization == null)
localization = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME;
URL baseNLS = target.getEntry(localization + ".properties");
if (baseNLS == null)
return false;
int lastSlash = localization.lastIndexOf('/');
if (lastSlash == localization.length() - 1)
return false;
String baseDir = lastSlash < 0 ? "" : localization.substring(0, lastSlash);
String filePattern = (lastSlash < 0 ? localization : localization.substring(lastSlash + 1)) + "_*.properties";
Enumeration<?> nlsFiles = fragment.findEntries(baseDir, filePattern, false);
return nlsFiles != null;
}
private static boolean isSingleton(Bundle bundle) {
Dictionary<?, ?> allHeaders = bundle.getHeaders("");
String symbolicNameHeader = (String) allHeaders.get(Constants.BUNDLE_SYMBOLICNAME);
try {
if (symbolicNameHeader != null) {
ManifestElement[] symbolicNameElements = ManifestElement.parseHeader(Constants.BUNDLE_SYMBOLICNAME, symbolicNameHeader);
if (symbolicNameElements.length > 0) {
String singleton = symbolicNameElements[0].getDirective(Constants.SINGLETON_DIRECTIVE);
if (singleton == null)
singleton = symbolicNameElements[0].getAttribute(Constants.SINGLETON_DIRECTIVE);
if (!"true".equalsIgnoreCase(singleton)) {
String manifestVersion = (String) allHeaders.get(org.osgi.framework.Constants.BUNDLE_MANIFESTVERSION);
if (manifestVersion == null) {
if (OSGIUtils.getDefault().getBundle(symbolicNameElements[0].getValue()) == bundle)
return true;
}
return false;
}
}
}
} catch (BundleException e1) {
}
return true;
}
}