package org.eclipse.core.runtime; | |
/* | |
* Licensed Materials - Property of IBM, | |
* WebSphere Studio Workbench | |
* (c) Copyright IBM Corp 2000 | |
*/ | |
import org.eclipse.core.internal.plugins.DefaultPlugin; | |
import org.eclipse.core.internal.plugins.PluginDescriptor; | |
import org.eclipse.core.internal.runtime.*; | |
import java.util.StringTokenizer; | |
import java.util.Vector; | |
import java.net.*; | |
import java.io.InputStream; | |
import java.io.IOException; | |
/** | |
* The abstract superclass of all plug-in runtime class | |
* implementations. A plug-in subclasses this class and overrides | |
* the <code>startup</code> and <code>shutdown</code> methods | |
* in order to react to life cycle requests automatically issued | |
* by the platform. | |
* <p> | |
* Conceptually, the plug-in runtime class represents the entire plug-in | |
* rather than an implementation of any one particular extension the | |
* plug-in declares. A plug-in is not required to explicitly | |
* specify a plug-in runtime class; if none is specified, the plug-in | |
* will be given a default plug-in runtime object that ignores all life | |
* cycle requests (it still provides access to the corresponding | |
* plug-in descriptor). | |
* </p> | |
* <p> | |
* In the case of more complex plug-ins, it may be desireable | |
* to define a concrete subclass of <code>Plugin</code>. | |
* However, just subclassing <code>Plugin</code> is not | |
* sufficient. The name of the class must be explicitly configured | |
* in the plug-in's manifest (<code>plugin.xml</code>) file | |
* with the class attribute of the <code><plugin></code> element markup. | |
* </p> | |
* <p> | |
* Instances of plug-in runtime classes are automatically created | |
* by the platform in the course of plug-in activation. | |
* <b>Clients must never explicitly instantiate a plug-in runtime class</b>. | |
* </p> | |
* <p> | |
* A typical implementation pattern for plug-in runtime classes is to | |
* provide a static convenience method to gain access to a plug-in's | |
* runtime object. This way, code in other parts of the plug-in | |
* implementation without direct access to the plug-in runtime object | |
* can easily obtain a reference to it, and thence to any plug-in-wide | |
* resources recorded on it. An example follows: | |
* <pre> | |
* package myplugin; | |
* public class MyPluginClass extends Plugin { | |
* private static MyPluginClass instance; | |
* | |
* public static MyPluginClass getInstance() { return instance; } | |
* | |
* public void MyPluginClass(IPluginDescriptor descriptor) { | |
* super(descriptor); | |
* instance = this; | |
* // ... other initialization | |
* } | |
* // ... other methods | |
* } | |
* </pre> | |
* In the above example, a call to <code>MyPluginClass.getInstance()</code> | |
* will always return an initialized instance of <code>MyPluginClass</code>. | |
* </p> | |
* <p> | |
* The static method <code>Platform.getPlugin()</code> | |
* can be used to locate a plug-in's runtime object by name. | |
* The extension initialization would contain the following code: | |
* <pre> | |
* Plugin myPlugin = Platform.getPlugin("com.example.myplugin"); | |
* </pre> | |
* | |
* Another typical implementation pattern for plug-in classes | |
* is handling of any initialization files required by the plug-in. | |
* Typically, each plug-in will ship one or more default files | |
* as part of the plug-in install. The executing plug-in will | |
* use the defaults on initial startup (or when explicitly requested | |
* by the user), but will subsequently rewrite any modifications | |
* to the default settings into one of the designated plug-in | |
* working directory locations. An example of such an implementation | |
* pattern is illustrated below: | |
* <pre> | |
* package myplugin; | |
* public class MyPlugin extends Plugin { | |
* | |
* private static final String INI = "myplugin.ini"; | |
* private Properties myProperties = null; | |
* | |
* public void startup() throws CoreException { | |
* try { | |
* InputStream input = null; | |
* // look for working properties. If none, use shipped defaults | |
* File file = getStateLocation().append(INI).toFile(); | |
* if (!file.exists()) { | |
* URL base = getDescriptor().getInstallURL(); | |
* input = (new URL(base,INI)).openStream(); | |
* } else | |
* input = new FileInputStream(file); | |
* | |
* // load properties | |
* try { | |
* myProperties = new Properties(); | |
* myProperties.load(input); | |
* } finally { | |
* try { | |
* input.close(); | |
* } catch (IOException e) { | |
* // ignore failure on close | |
* } | |
* } | |
* } catch (Exception e) { | |
* throw new CoreException( | |
* new Status(IStatus.ERROR, getDescriptor().getUniqueIdentifier(), | |
* 0, "Problems starting plug-in myplugin", e)); | |
* } | |
* } | |
* | |
* public void shutdown() throws CoreException { | |
* // save properties in plugin state location (r/w) | |
* try { | |
* FileOutputStream output = null; | |
* try { | |
* output = new FileOutputStream(getStateLocation().append(INI)); | |
* myProperties.store(output, null); | |
* } finally { | |
* try { | |
* output.close(); | |
* } catch (IOException e) { | |
* // ignore failure on close | |
* } | |
* } | |
* } catch (Exception e) { | |
* throw new CoreException( | |
* new Status(IStatus.ERROR, getDescriptor().getUniqueIdentifier(), | |
* 0, "Problems shutting down plug-in myplugin", e)); | |
* } | |
* } | |
* | |
* public Properties getProperties() { | |
* return myProperties; | |
* } | |
* } | |
* </pre> | |
* </p> | |
*/ | |
public abstract class Plugin { | |
/** | |
* The debug flag for this plug-in. The flag is false by default. | |
* It can be set to true either by the plug-in itself or in the platform | |
* debug options. | |
*/ | |
private boolean debug = false; | |
/** The plug-in descriptor. | |
*/ | |
private IPluginDescriptor descriptor; | |
/** | |
* Creates a new plug-in runtime object for the given plug-in descriptor. | |
* <p> | |
* Instances of plug-in runtime classes are automatically created | |
* by the platform in the course of plug-in activation. | |
* <b>Cliens must never explicitly instantiate a plug-in runtime class.</b> | |
* </p> | |
* | |
* @param descriptor the plug-in descriptor | |
* @see #getDescriptor | |
*/ | |
public Plugin(IPluginDescriptor descriptor) { | |
Assert.isNotNull(descriptor); | |
Assert.isTrue(!descriptor.isPluginActivated(), Policy.bind("pluginConstructInvalid", new String[] {})); | |
String className = ((PluginDescriptor) descriptor).getPluginClass(); | |
if (this.getClass() == DefaultPlugin.class) { | |
Assert.isTrue(className == null || className.equals(""), Policy.bind("pluginConstructInvalid", new String[] {})); | |
} else { | |
Assert.isTrue(this.getClass().getName().equals(className), Policy.bind("pluginConstructInvalid", new String[] {})); | |
} | |
this.descriptor = descriptor; | |
String key = descriptor.getUniqueIdentifier() + "/debug"; | |
String value = Platform.getDebugOption(key); | |
this.debug = value == null ? false : value.equalsIgnoreCase("true"); | |
} | |
/** | |
* Returns a URL for the given path. Returns <code>null</code> if the URL | |
* could not be computed or created. | |
* | |
* @param file path relative to plug-in installation location | |
* @return a URL for the given path or <code>null</code> | |
*/ | |
public final URL find(IPath path) { | |
String first = path.segment(0); | |
if (first.charAt(0) != '$') { | |
try { | |
return new URL(getDescriptor().getInstallURL(), path.toString()); | |
} catch (MalformedURLException e) { | |
return null; | |
} | |
} | |
if (first.equalsIgnoreCase("$nl$")) | |
return null; | |
if (first.equalsIgnoreCase("$os$")) | |
return null; | |
if (first.equalsIgnoreCase("$ws$")) | |
return null; | |
if (first.equalsIgnoreCase("$files$")) | |
return null; | |
return null; | |
} | |
/** | |
* Returns the plug-in descriptor for this plug-in runtime object. | |
* | |
* @return the plug-in descriptor for this plug-in runtime object | |
*/ | |
public final IPluginDescriptor getDescriptor() { | |
return descriptor; | |
} | |
/** | |
* Returns the log for this plug-in. If no such log exists, one is created. | |
* | |
* @return the log for this plug-in | |
*/ | |
public final ILog getLog() { | |
return InternalPlatform.getLog(this); | |
} | |
/** | |
* Returns the location in the local file system of the | |
* plug-in state area for this plug-in. | |
* If the plug-in state area did not exist prior to this call, | |
* it is created. | |
* <p> | |
* The plug-in state area is a file directory within the | |
* platform's metadata area where a plug-in is free to create files. | |
* The content and structure of this area is defined by the plug-in, | |
* and the particular plug-in is solely responsible for any files | |
* it puts there. It is recommended for plug-in preference settings and | |
* other configuration parameters. | |
* </p> | |
* | |
* @return a local file system path | |
*/ | |
public final IPath getStateLocation() { | |
return InternalPlatform.getPluginStateLocation(this); | |
} | |
/** | |
* Returns whether this plug-in is in debug mode. | |
* By default plug-ins are not in debug mode. A plug-in can put itself | |
* into debug mode or the user can set an execution option to do so. | |
* | |
* @return whether this plug-in is in debug mode | |
*/ | |
public boolean isDebugging() { | |
return debug; | |
} | |
/** | |
* Returns an input stream for the specified file. The file path | |
* must be specified relative this the plug-in's installation location. | |
* | |
* @param file path relative to plug-in installation location | |
* @return an input stream | |
* @see #openStream(IPath,boolean) | |
*/ | |
public final InputStream openStream(IPath file) throws IOException { | |
return openStream(file, false); | |
} | |
/** | |
* Returns an input stream for the specified file. The file path | |
* must be specified relative to this plug-in's installation location. | |
* Optionally, the platform searches for the correct localized version | |
* of the specified file using the users current locale, and Java | |
* naming convention for localized resource files (locale suffix appended | |
* to the specified file extension). | |
* <p> | |
* The caller must close the returned stream when done. | |
* </p> | |
* | |
* @param file path relative to plug-in installation location | |
* @param localized <code>true</code> for the localized version | |
* of the file, and <code>false</code> for the file exactly | |
* as specified | |
* @return an input stream | |
*/ | |
public final InputStream openStream(IPath file, boolean localized) throws IOException { | |
URL target = new URL(getDescriptor().getInstallURL() + file.toString()); | |
return target.openStream(); | |
} | |
/** | |
* Sets whether this plug-in is in debug mode. | |
* By default plug-ins are not in debug mode. A plug-in can put itself | |
* into debug mode or the user can set a debug option to do so. | |
* | |
* @param value whether or not this plugi-in is in debug mode | |
*/ | |
public void setDebugging(boolean value) { | |
debug = value; | |
} | |
/** | |
* Shuts down this plug-in and discards all plug-in state. | |
* <p> | |
* This method should be re-implemented in subclasses that need to do something | |
* when the plug-in is shut down. Implementors should call the inherited method | |
* to ensure that any system requirements can be met. | |
* </p> | |
* <p> | |
* Plug-in shutdown code should be robust. In particular, this method | |
* should always make an effort to shut down the plug-in. Furthermore, | |
* the code should not assume that the plug-in was started successfully, | |
* as this method will be invoked in the event of a failure during startup. | |
* </p> | |
* <p> | |
* Note 1: If a plug-in has been started, this method will be automatically | |
* invoked by the platform when the platform is shut down. | |
* </p> | |
* <p> | |
* Note 2: This method is intended to perform simple termination | |
* of the plug-in environment. The platform may terminate invocations | |
* that do not complete in a timely fashion. | |
* </p> | |
* <b>Cliens must never explicitly call this method.</b> | |
* | |
* @exception CoreException if this method fails to shut down | |
* this plug-in | |
*/ | |
public void shutdown() throws CoreException { | |
} | |
/** | |
* Starts up this plug-in. | |
* <p> | |
* This method should be overridden in subclasses that need to do something | |
* when this plug-in is started. Implementors should call the inherited method | |
* to ensure that any system requirements can be met. | |
* </p> | |
* <p> | |
* If this method throws an exception, it is taken as an indication that | |
* plug-in initialization has failed; as a result, the plug-in will not | |
* be activated; moreover, the plug-in will be marked as disabled and | |
* ineligible for activation for the duration. | |
* </p> | |
* <p> | |
* Plug-in startup code should be robust. In the event of a startup failure, | |
* the plug-in's <code>shutdown</code> method will be invoked automatically, | |
* in an attempt to close open files, etc. | |
* </p> | |
* <p> | |
* Note 1: This method is automatically invoked by the platform | |
* the first time any code in the plug-in is executed. | |
* </p> | |
* <p> | |
* Note 2: This method is intended to perform simple initialization | |
* of the plug-in environment. The platform may terminate initializers | |
* that do not complete in a timely fashion. | |
* </p> | |
* <b>Cliens must never explicitly call this method.</b> | |
* | |
* @exception CoreException if this plug-in did not start up properly | |
*/ | |
public void startup() throws CoreException { | |
} | |
/** | |
* Returns a string representation of the plug-in, suitable | |
* for debugging purposes only. | |
*/ | |
public String toString() { | |
return descriptor.toString(); | |
} | |
} |