/**
* <copyright>
*
* Copyright (c) 2002, 2010 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 - Initial API and implementation
*
* </copyright>
*
* $Id: EMFPlugin.java,v 1.21 2008/04/08 15:00:50 emerks Exp $
*/
package net.enilink.komma.common;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.jar.Manifest;
import net.enilink.komma.common.internal.CommonStatusCodes;
import net.enilink.komma.common.util.DelegatingResourceLocator;
import net.enilink.komma.common.util.ILogger;
import net.enilink.komma.common.util.IResourceLocator;
import net.enilink.komma.common.util.WrappedException;
import net.enilink.komma.core.URI;
import net.enilink.komma.core.URIs;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.Bundle;
/**
* MF must run within an Eclipse workbench, within a headless Eclipse workspace,
* or just stand-alone as part of some other application. To support this, all
* resource access (e.g., NL strings, images, and so on) is directed to the
* resource locator methods, which can redirect the service as appropriate to
* the runtime. During Eclipse invocation, the implementation delegates to a
* plugin implementation. During stand-alone invocation, no plugin
* initialization takes place, so the implementation delegates to a resource JAR
* on the CLASSPATH. The resource jar will typically <b>not</b> be on the
* CLASSPATH during Eclipse invocation. It will contain things like the icons
* and the .properties, which are available in a different way during Eclipse
* invocation.
*
* @see DelegatingResourceLocator
* @see IResourceLocator
* @see ILogger
*/
public abstract class AbstractKommaPlugin extends DelegatingResourceLocator
implements IResourceLocator, ILogger {
public static final boolean IS_ECLIPSE_RUNNING;
static {
boolean result = false;
try {
result = Platform.isRunning();
} catch (Throwable exception) {
// Assume that we aren't running.
}
IS_ECLIPSE_RUNNING = result;
}
public static final boolean IS_RESOURCES_BUNDLE_AVAILABLE;
static {
boolean result = false;
if (IS_ECLIPSE_RUNNING) {
try {
Bundle resourcesBundle = Platform
.getBundle("org.eclipse.core.resources");
result = resourcesBundle != null
&& (resourcesBundle.getState() & (Bundle.ACTIVE
| Bundle.STARTING | Bundle.RESOLVED)) != 0;
} catch (Throwable exception) {
// Assume that it's not available.
}
}
IS_RESOURCES_BUNDLE_AVAILABLE = result;
}
protected IResourceLocator[] delegateResourceLocators;
public AbstractKommaPlugin(IResourceLocator[] delegateResourceLocators) {
this.delegateResourceLocators = delegateResourceLocators;
}
/**
* Returns an Eclipse plugin implementation of a resource locator.
*
* @return an Eclipse plugin implementation of a resource locator.
*/
public abstract IResourceLocator getBundleResourceLocator();
@Override
final protected IResourceLocator getPrimaryResourceLocator() {
return getBundleResourceLocator();
}
@Override
protected IResourceLocator[] getDelegateResourceLocators() {
return delegateResourceLocators;
}
/**
* Returns an Eclipse plugin implementation of a logger.
*
* @return an Eclipse plugin implementation of a logger.
*/
public ILogger getPluginLogger() {
return (ILogger) getBundleResourceLocator();
}
public String getSymbolicName() {
IResourceLocator resourceLocator = getBundleResourceLocator();
if (resourceLocator instanceof InternalEclipsePlugin) {
return ((InternalEclipsePlugin) resourceLocator).getSymbolicName();
} else {
String result = getClass().getName();
return result.substring(0, result.lastIndexOf('.'));
}
}
/*
* Javadoc copied from interface.
*/
public void log(Object logEntry) {
ILogger logger = getPluginLogger();
if (logger == null) {
if (logEntry instanceof Throwable) {
((Throwable) logEntry).printStackTrace(System.err);
} else {
System.err.println(logEntry);
}
} else {
logger.log(logEntry);
}
}
/**
* The actual implementation of an Eclipse <b>Plugin</b>.
*/
public static abstract class EclipsePlugin extends Plugin implements
IResourceLocator, ILogger, InternalEclipsePlugin {
/**
* The EMF plug-in APIs are all delegated to this helper, so that code
* can be shared by plug-in implementations with a different platform
* base class (e.g. AbstractUIPlugin).
*/
protected InternalHelper helper;
/**
* Creates an instance.
*/
public EclipsePlugin() {
helper = new InternalHelper(this);
}
/**
* Return the plugin ID.
*/
public String getSymbolicName() {
return helper.getSymbolicName();
}
/*
* Javadoc copied from interface.
*/
public URL getBaseURL() {
return helper.getBaseURL();
}
/*
* Javadoc copied from interface.
*/
public Object getImage(String key) {
try {
return doGetImage(key);
} catch (MalformedURLException exception) {
throw new WrappedException(exception);
} catch (IOException exception) {
throw new MissingResourceException(
CommonPlugin.INSTANCE.getString(
"_UI_StringResourceNotFound_exception",
new Object[] { key }), getClass().getName(),
key);
}
}
/**
* Does the work of fetching the image associated with the key. It
* ensures that the image exists.
*
* @param key
* the key of the image to fetch.
* @exception IOException
* if an image doesn't exist.
* @return the description of the image associated with the key.
*/
protected Object doGetImage(String key) throws IOException {
return helper.getImage(key);
}
public String getString(String key) {
return helper.getString(key, true);
}
public String getString(String key, boolean translate) {
return helper.getString(key, translate);
}
public String getString(String key, Object... substitutions) {
return helper.getString(key, substitutions, true);
}
public String getString(String key, Object[] substitutions,
boolean translate) {
return helper.getString(key, substitutions, translate);
}
public void log(Object logEntry) {
helper.log(logEntry);
}
}
/**
* This just provides a common interface for the Eclipse plugins supported
* by EMF. It is not considered API and should not be used by clients.
*/
public static interface InternalEclipsePlugin {
String getSymbolicName();
}
/**
* This just provides a common delegate for non-UI and UI plug-in classes.
* It is not considered API and should not be used by clients.
*/
public static class InternalHelper {
protected Plugin plugin;
protected ResourceBundle resourceBundle;
protected ResourceBundle untranslatedResourceBundle;
public InternalHelper(Plugin plugin) {
this.plugin = plugin;
}
protected Bundle getBundle() {
return plugin.getBundle();
}
protected ILog getLog() {
return plugin.getLog();
}
/**
* Return the plugin ID.
*/
public String getSymbolicName() {
return getBundle().getSymbolicName();
}
public URL getBaseURL() {
return getBundle().getEntry("/");
}
/**
* Fetches the image associated with the given key. It ensures that the
* image exists.
*
* @param key
* the key of the image to fetch.
* @exception IOException
* if an image doesn't exist.
* @return the description of the image associated with the key.
*/
public Object getImage(String key) throws IOException {
URL url = new URL(getBaseURL() + "icons/" + key + extensionFor(key));
InputStream inputStream = url.openStream();
inputStream.close();
return url;
}
public String getString(String key, boolean translate) {
ResourceBundle bundle = translate ? resourceBundle
: untranslatedResourceBundle;
if (bundle == null) {
if (translate) {
bundle = resourceBundle = Platform
.getResourceBundle(getBundle());
} else {
String resourceName = getBaseURL().toString()
+ "plugin.properties";
try {
InputStream inputStream = new URL(resourceName)
.openStream();
bundle = untranslatedResourceBundle = new PropertyResourceBundle(
inputStream);
inputStream.close();
} catch (IOException ioException) {
throw new MissingResourceException(
"Missing properties: " + resourceName,
getClass().getName(), "plugin.properties");
}
}
}
return bundle.getString(key);
}
public String getString(String key, Object[] substitutions,
boolean translate) {
return MessageFormat.format(getString(key, translate),
substitutions);
}
public void log(Object logEntry) {
IStatus status;
if (logEntry instanceof IStatus) {
status = (IStatus) logEntry;
getLog().log(status);
} else {
if (logEntry == null) {
logEntry = new RuntimeException(getString(
"_UI_NullLogEntry_exception", true))
.fillInStackTrace();
}
if (logEntry instanceof Throwable) {
Throwable throwable = (Throwable) logEntry;
// System.err.println("Logged throwable: --------------------");
// throwable.printStackTrace();
String message = throwable.getLocalizedMessage();
if (message == null) {
message = "";
}
getLog().log(
new Status(IStatus.WARNING, getBundle()
.getSymbolicName(), 0, message, throwable));
} else {
// System.err.println("Logged throwable: --------------------");
// throwable.printStackTrace();
getLog().log(
new Status(IStatus.WARNING, getBundle()
.getSymbolicName(), 0, logEntry.toString(),
null));
}
}
}
public void logErrorMessage(String message) {
log(new Status(IStatus.ERROR, getBundle().getSymbolicName(),
CommonStatusCodes.INTERNAL_ERROR, message, null));
}
public void logErrorStatus(String message, IStatus status) {
if (status == null) {
logErrorMessage(message);
return;
}
MultiStatus multi = new MultiStatus(getBundle().getSymbolicName(),
CommonStatusCodes.INTERNAL_ERROR, message, null);
multi.add(status);
log(multi);
}
}
public static void main(String[] args) {
try {
String[] relativePath = { "META-INF", "MANIFEST.MF" };
Class<?> theClass = args.length > 0 ? Class.forName(args[0])
: AbstractKommaPlugin.class;
String className = theClass.getName();
int index = className.lastIndexOf(".");
URL classURL = theClass.getResource((index == -1 ? className
: className.substring(index + 1)) + ".class");
URI uri = URIs.createURI(classURL.toString());
// Trim off the segments corresponding to the package nesting.
//
int count = 1;
for (int i = 0; (i = className.indexOf('.', i)) != -1; ++i) {
++count;
}
uri = uri.trimSegments(count);
URL manifestURL = null;
// For an archive URI, check for the path in the archive.
//
if (URIs.isArchiveScheme(uri.scheme())) {
try {
// If we can open an input stream, then the path is there,
// and we have a good URL.
//
String manifestURI = uri.appendSegments(relativePath)
.toString();
InputStream inputStream = new URL(manifestURI).openStream();
inputStream.close();
manifestURL = new URL(manifestURI);
} catch (IOException exception) {
// If the path isn't within the root of the archive,
// create a new URI for the folder location of the archive,
// so we can look in the folder that contains it.
//
uri = URIs.createURI(uri.authority()).trimSegments(1);
}
}
// If we didn't find the path in the usual place nor in the
// archive...
//
if (manifestURL == null) {
// Trim off the "bin" or "runtime" segment.
//
String lastSegment = uri.lastSegment();
if ("bin".equals(lastSegment) || "runtime".equals(lastSegment)) {
uri = uri.trimSegments(1);
}
uri = uri.appendSegments(relativePath);
manifestURL = new URL(uri.toString());
}
Manifest manifest = new Manifest(manifestURL.openStream());
String symbolicName = manifest.getMainAttributes().getValue(
"Bundle-SymbolicName");
if (symbolicName != null) {
int end = symbolicName.indexOf(";");
if (end != -1) {
symbolicName = symbolicName.substring(0, end);
}
System.out.println("Bundle-SymbolicName="
+ symbolicName
+ " Bundle-Version="
+ manifest.getMainAttributes().getValue(
"Bundle-Version"));
return;
}
} catch (Exception exception) {
// Just print an error message.
}
System.err.println("No Bundle information found");
}
}