/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.core.designer.plugin; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.teiid.core.designer.CoreModelerPlugin; import org.teiid.core.designer.util.CoreArgCheck; /** * This class provides static methods to perform the following plugin-related activities: * <ul> * <li>Instantiate application plugin extension classes, which automatically starts the plugin framework if neccessary,</li> * <li>Instantiate other plugin extension classes,</li> * <li>Get access to extensions, and</li> * <li>Shutdown the plugin framework</li> * </ul> * Note that if you do not shutdown the plugin framework after instantiating an application, the application will never terminate. * * * @since 8.0 */ public abstract class PluginUtilities { private static final String PLUGINS_FOLDER = "plugins"; //$NON-NLS-1$ private static final String BOOT_PLUGIN_FOLDER = "org.eclipse.core.boot"; //$NON-NLS-1$ private static final String BOOT_JAR = "boot.jar"; //$NON-NLS-1$ private static final String PROTOCOL = "file"; //$NON-NLS-1$ private static final String BOOT_LOADER = "org.eclipse.core.boot.BootLoader"; //$NON-NLS-1$ private static final String TEMPORARY_METADATA_PATH = System.getProperty("java.io.tmpdir") + "metamatrix"; //$NON-NLS-1$ //$NON-NLS-2$ private static final String STARTUP_METHOD = "startup"; //$NON-NLS-1$ private static final int BOOT_PLUGIN_FOLDER_NOT_FOUND_CODE = 0; private static final String BOOT_PLUGIN_FOLDER_NOT_FOUND_MESSAGE = CoreModelerPlugin.Util.getString("PluginUtilities.Could_not_find___12") + BOOT_PLUGIN_FOLDER + CoreModelerPlugin.Util.getString("PluginUtilities.__folder._13"); //$NON-NLS-1$ //$NON-NLS-2$ private static final String CONSTRUCTOR_MESSAGE = CoreModelerPlugin.Util.getString("PluginUtilities.Make_sure_the_executable_extension_class_contains_a_public_constructor_14") + //$NON-NLS-1$ CoreModelerPlugin.Util.getString("PluginUtilities._with_no_arguments._15"); //$NON-NLS-1$ private static Class bootLoader; private static String[] startupArgs = new String[0]; /** * Creates an instance of a class defined by the specified plugin extension, using the value of the specified attribute * defined within the specified extension's child element as a fully-qualified class name. * * @param extension The extension that defines the class to instantiate. * @param element The child element of the extension containing <code>attribute</code>. * @param attribute The attribute of <code>element</code> that specifies the fully-qualified class name to instantiate. * @return A class instance, or null if either the element or attribute is not found. * @throws CoreException If the class instance could not be created for any reason. * @since 3.1 */ public static Object createExecutableExtension( final IExtension extension, final String element, final String attribute ) throws CoreException { try { final IConfigurationElement[] elems = extension.getConfigurationElements(); for (int ndx = 0, count = elems.length; ndx < count; ++ndx) { IConfigurationElement elem = elems[ndx]; if (elem.getName().equals(element)) { return elem.createExecutableExtension(attribute); } } return null; } catch (final CoreException err) { if (err.getStatus().getException() instanceof InstantiationException) { System.err.println(CONSTRUCTOR_MESSAGE); } throw err; } } /** * Returns the extension identified by the specified fully-qualified ID and contained within the specified list of extensions. * * @param id The fully-qualified ID of the extension. * @param extensions The array of extensions to be searched. * @return An extension, or null if no extension with the specified ID is found in the array. * @since 3.1 */ public static IExtension getExtension( final String id, final IExtension[] extensions ) { for (int ndx = 0, count = extensions.length; ndx < count; ++ndx) { final IExtension extension = extensions[ndx]; final String uniqueId = extension.getUniqueIdentifier(); if (uniqueId != null && uniqueId.equals(id)) { return extension; } } return null; } /** * Returns all extensions of the extension point identified by the specified fully-qualified ID. * * @param id The fully-qualified ID of the extension point. * @return The extension point's extensions, or an emply array if no extension point with the specified ID is found. * @since 3.1 */ public static IExtension[] getExtensions( final String id ) { // final IExtensionRegistry registry = Platform.getExtensionRegistry(); // if (registry != null) { // return registry.getExtensions(id); // } // return new IExtension[0]; final IExtensionRegistry registry = Platform.getExtensionRegistry(); if (registry != null) { final IExtensionPoint point = registry.getExtensionPoint(id); if (point == null) { return new IExtension[0]; } return point.getExtensions(); } return new IExtension[0]; } /* * (non-Javadoc) * @see org.eclipse.core.runtime.IExtensionRegistry#getConfigurationElementsFor(java.lang.String) */ public static IConfigurationElement[] getConfigurationElementsFor( final String id ) { return Platform.getExtensionRegistry().getConfigurationElementsFor(id); } /** * Starts up the plugin framework located at the specified install path, and which uses the specified metadata path to store * metadata. * * @param installPath The path identifying the folder where the application is installed. * @param metadataPath The path identifying the folder under which the Eclipse metadata folder should be created. * @return An instance of ApplicationExtension, or null if no extension with the specified ID is found. * @throws ClassNotFoundException If the BootLoader class could not be found in the boot jar file. * @throws CoreException If the boot plugin folder could not be found. * @throws IllegalAccessException If one of the reflectively accessed BootLoader methods is not public. * @throws InvocationTargetException If one of the reflectively called BootLoader methods throws a {@link RuntimeException}. * @throws MalformedURLException If installPath contains an invalid path. * @throws NoSuchMethodException If one of the reflectively accessed BootLoader or ApplicationExtension methods does not * exist. * @since 3.1 */ public static void startup( String installPath, String metadataPath ) throws ClassNotFoundException, CoreException, IllegalAccessException, InvocationTargetException, MalformedURLException, NoSuchMethodException { CoreArgCheck.isNotEmpty(installPath, CoreModelerPlugin.Util.getString("PluginUtilities.The_installation_path_must_not_be_empty._18")); //$NON-NLS-1$ // If it hasn't already been done, get the boot loader needed to instantiate the application extension. The boot loader // must be loaded using reflection since it also is defined as a plugin, and the plugin directory is not typically in the // classpath. if (PluginUtilities.bootLoader == null) { if (metadataPath == null) { metadataPath = TEMPORARY_METADATA_PATH; } // Append the plugins folder name to the install path final StringBuffer bootFolderPath = new StringBuffer(installPath); final char lastChr = bootFolderPath.charAt(bootFolderPath.length() - 1); if (lastChr != '/' && lastChr != '\\') { bootFolderPath.append('/'); } bootFolderPath.append(PLUGINS_FOLDER); // Look for the boot plugin folder under the plugins folder final File[] bootPluginFolders = new File(bootFolderPath.toString()).listFiles(new FileFilter() { @Override public boolean accept( final File file ) { if (file.isDirectory() && file.getName().startsWith(BOOT_PLUGIN_FOLDER)) { return true; } return false; } }); if (bootPluginFolders.length == 0) { final IStatus status = new Status(IStatus.ERROR, BOOT_PLUGIN_FOLDER, BOOT_PLUGIN_FOLDER_NOT_FOUND_CODE, BOOT_PLUGIN_FOLDER_NOT_FOUND_MESSAGE, null); throw new CoreException(status); } // Append the relative path of the boot.jar file to the first boot plugin folder found final String bootJarPath = new File(bootPluginFolders[0], BOOT_JAR).getAbsolutePath().replace(File.separatorChar, '/'); // Load the BootLoader class from the boot.jar file final URL bootUrl = new URL(PROTOCOL, null, bootJarPath); URLClassLoader loader = null; try { loader = new URLClassLoader(new URL[] {bootUrl}, null); final Class bootLoader = loader.loadClass(BOOT_LOADER); // Initialize boot loader, again using reflection since the class is defined in a plugin, by passing the metadata // directory to the startup method. This initializes the files Eclipse needs in the metadata directory and performs // initial processing of the plugins directory (whatever that entails). The plugins directory is apparently located // based upon the path used to load the boot.jar. final Method startupMeth = bootLoader.getMethod(STARTUP_METHOD, new Class[] {URL.class, String.class, String[].class}); startupMeth.invoke(bootLoader, new Object[] {null, metadataPath, PluginUtilities.startupArgs}); // Get access to boot loader's getRunnableMethod for future instantiations of application extensions PluginUtilities.bootLoader = bootLoader; } finally { if (loader != null) try { loader.close(); } catch (IOException ex) { //Nothing to do } } } } }