| /******************************************************************************* |
| * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jem.internal.proxy.core; |
| /* |
| * $RCSfile: ProxyPlugin.java,v $ |
| * $Revision: 1.52 $ $Date: 2005/06/21 19:36:48 $ |
| */ |
| |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.util.*; |
| import java.util.logging.Level; |
| |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.debug.core.*; |
| import org.eclipse.jdt.core.*; |
| import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
| import org.eclipse.osgi.service.resolver.BundleSpecification; |
| import org.osgi.framework.*; |
| |
| import org.eclipse.jem.util.logger.proxy.Logger; |
| import org.eclipse.jem.util.logger.proxyrender.EclipseLogger; |
| |
| |
| /** |
| * The plugin class for the org.eclipse.jem.internal.proxy.core plugin. |
| */ |
| |
| public class ProxyPlugin extends Plugin { |
| |
| /** |
| * This interface is for a listener that needs to know if this plugin (ProxyPlugin) is being shutdown. |
| * It is needed because there are some extensions that get added dynamically that need to know when the |
| * plugin is being shutdown. Can't use new bundle listener for this because it notifies AFTER shutdown. |
| * |
| * @since 1.0.0 |
| */ |
| public interface IProxyPluginShutdownListener { |
| /** |
| * ProxyPlugin is in shutdown. |
| * |
| * @since 1.0.0 |
| */ |
| public void shutdown(); |
| } |
| |
| private static ProxyPlugin PROXY_PLUGIN = null; |
| public static final String PREFERENCES_VM_NOVERIFY_KEY = "JEM_PREFERENCES_VM_NOVERIFY_KEY"; // Key for NOVERIFY option of VM //$NON-NLS-1$ |
| public static final String PDE_NATURE_ID = "org.eclipse.pde.PluginNature" ; //$NON-NLS-1$ |
| |
| // If this is set to true, then in development mode and it will try for proxy jars in directories. |
| private boolean devMode; |
| |
| private ListenerList shutdownListeners; |
| |
| public ProxyPlugin() { |
| super(); |
| PROXY_PLUGIN = this; |
| devMode = Platform.inDevelopmentMode(); |
| } |
| |
| /** |
| * Access the singleton |
| * @return the singleton plugin |
| * |
| * @since 1.0.0 |
| */ |
| public static ProxyPlugin getPlugin() { |
| return PROXY_PLUGIN; |
| } |
| |
| private Logger logger; |
| public Logger getLogger() { |
| if (logger == null) |
| logger = EclipseLogger.getEclipseLogger(this); |
| return logger; |
| } |
| |
| /** |
| * This will take the bundle and file name and make it local and return that |
| * fully qualified. It will look in fragments, but only returns first found. If there can be multiples use |
| * the one for bundles and it fragments. |
| * <p> |
| * If we are in development and it will pick it up from the path |
| * that is listed in the proxy.jars file located in the bundle passed in. This allows development code to be |
| * used in place of the actual runtime jars. If the runtime jars are found, |
| * they will be used. |
| * <p> |
| * For example if looking for file runtime/xyz.jar in bundle abc, then in bundle directory for abc, |
| * there should be a file called proxy.jars. This should only be in development, this file should not |
| * be distributed for production. It would be distributed in the SDK environment when testing is desired. |
| * <p> |
| * The format of the file is: |
| * runtimefile=/projectname/builddirectory |
| * <p> |
| * For this to work when the actual jar is not found, the Eclipse must of been started in |
| * dev mode (i.e. the bundle location will be a project within the developer Eclipse. That way |
| * we can go up one level for the current install location and assume the above projectname |
| * will be found relative to the directory. |
| * <p> |
| * For the above example: |
| * runtime/xyz.jar=/xyzproject/bin |
| * <p> |
| * It will return "." if file can't be found. It means nothing but it won't cause jvm to crash. |
| * |
| * @param bundle |
| * @param filenameWithinBundle |
| * @return the path to the file or <code>"."</code> if not found. |
| * |
| * @since 1.0.0 |
| */ |
| public String localizeFromBundleOnly(Bundle bundle, String filenameWithinBundle) { |
| URL url = urlLocalizeFromBundleOnly(bundle, filenameWithinBundle); |
| return url != null ? getFileFromURL(url) : "."; //$NON-NLS-1$ |
| } |
| public String localizeFromBundleAndFragments(Bundle bundle, String filenameWithinBundle) { |
| URL url = urlLocalizeFromBundleAndFragments(bundle, filenameWithinBundle); |
| return url != null ? getFileFromURL(url) : "."; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Just like localizeFromBundle except it will return an array of Strings. It will look for the filename |
| * within the bundle and any fragments of the bundle. If none are found, an empty array will be returned. |
| * <p> |
| * To find the files in the fragments that are in the runtime path (i.e. libraries), it will need to use a suffix, |
| * This is because the JDT will get confused if a runtime jar in a fragment has the same name |
| * as a runtime jar in the main bundle. |
| * NOTE: This is obsolete. JDT no longer has this problem. So we can find libraries in fragments that have the |
| * same file path. |
| * <p> |
| * So we will use the following search pattern: |
| * <ol> |
| * <li>Find in all of the fragments those that match the name exactly in the same paths if paths are supplied.</li> |
| * <li>Find in all of the fragments, in their runtime path (library stmt), those that match the name |
| * but have a suffix the same as the uniqueid of the fragment (preceeded by a period). This is so that it can be easily |
| * found but yet be unique in the entire list of fragments. For example if looking for "runtime/xyz.jar" |
| * and we have fragment "a.b.c.d.frag", then in the runtime path we will look for the file |
| * "runtime/xyz.a.b.c.d.frag.jar". Note: This is obsolete. Still here only for possible old code. Will go |
| * away in future.</li> |
| * <p> |
| * If the files in the fragments are not in the fragments library path then it can have the same name. NOTE: Obsolete, |
| * JDT can now handle same name. |
| * <p> |
| * This is useful for nls where the nls for the filename will be in one or more of the fragments of the plugin. |
| * |
| * @param bundle |
| * @param filenameWithinBundle |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| public String[] localizeAllFromBundleAndFragments(Bundle bundle, String filenameWithinBundle) { |
| URL[] urls = urlLocalizeAllFromBundleAndFragments(bundle, filenameWithinBundle); |
| String[] result = new String[urls.length]; |
| for (int i = 0; i < urls.length; i++) { |
| result[i] = getFileFromURL(urls[i]); |
| } |
| return result; |
| } |
| |
| private static String getFileFromURL(URL url) { |
| // We need to do this in a device independent way. The URL will always put a leading '/' in the |
| // file part of the URL, but on Windows we need to have this '/' removed. Some JRE's don't understand it. |
| return new File(url.getFile()).getAbsolutePath(); |
| |
| } |
| |
| public URL urlLocalizeFromBundleAndFragments(Bundle bundle, String filenameWithinBundle) { |
| return urlLocalizeFromBundleAndFragments(bundle, new Path(filenameWithinBundle)); |
| } |
| public URL urlLocalizeFromBundleAndFragments(Bundle bundle, IPath filenameWithinBundle) { |
| try { |
| URL pvm = Platform.find(bundle, filenameWithinBundle); |
| if (pvm != null) |
| return Platform.asLocalURL(pvm); |
| } catch (IOException e) { |
| } |
| if (devMode) { |
| URL[] urls = findDevAllFromBundleAndFragments(bundle, filenameWithinBundle.toString()); |
| if (urls.length > 0) |
| return urls[0]; |
| else |
| return null; |
| } else |
| return null; |
| } |
| |
| /** |
| * Like <code>localizeFromBundleAndFragments</code> except it returns URL's instead. |
| * |
| * @param bundle |
| * @param filenameWithinBundle |
| * @return |
| * |
| * @see ProxyPlugin#localizeFromBundleAndFragments(Bundle, String) |
| * @since 1.0.0 |
| */ |
| public URL[] urlLocalizeAllFromBundleAndFragments(Bundle bundle, String filenameWithinBundle) { |
| return urlLocalizeAllBundleAndFragments(bundle, Platform.getFragments(bundle), filenameWithinBundle); |
| } |
| public URL[] urlLocalizeAllFromBundleAndFragments(Bundle bundle, IPath filenameWithinBundle) { |
| return urlLocalizeAllBundleAndFragments(bundle, Platform.getFragments(bundle), filenameWithinBundle.toString()); |
| } |
| |
| /** |
| * @param bundle |
| * @param filenameWithinBundle |
| * @param fragments |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| private URL[] urlLocalizeAllBundleAndFragments(Bundle bundle, Bundle[] fragments, String filenameWithinBundle) { |
| |
| ArrayList urls = new ArrayList((fragments == null ? 0 : fragments.length) + 1); |
| URL url = internalUrlLocalizeFromBundleOnly(bundle, filenameWithinBundle); |
| if (url != null) |
| urls.add(url); |
| if (fragments != null) { |
| for (int i = 0; i < fragments.length; i++) { |
| Bundle fragment = fragments[i]; |
| url = internalUrlLocalizeFromBundleOnly(fragment, filenameWithinBundle); |
| if (url != null) |
| urls.add(url); |
| } |
| } |
| return (URL[]) urls.toArray(new URL[urls.size()]); |
| } |
| |
| private static final String PROXYJARS = "proxy.jars"; //$NON-NLS-1$ |
| |
| /** |
| * @see ProxyPlugin#localizeFromBundle(Bundle, String) |
| * |
| * This is just a helper to return a url instead. |
| * |
| * @param bundle |
| * @param filenameWithinBundle |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| public URL urlLocalizeFromBundleOnly(Bundle bundle, String filenameWithinBundle) { |
| // If the filenameWithinBundle begins with one of these special characters, |
| // it might be in a fragment. |
| if (filenameWithinBundle.charAt(0) == '$' |
| && (filenameWithinBundle.regionMatches(true, 0, "$nl$", 0, "$nl$".length()) //$NON-NLS-1$ //$NON-NLS-2$ |
| || filenameWithinBundle.regionMatches(true, 0, "$os$", 0, "$os$".length()) || filenameWithinBundle.regionMatches(true, 0, //$NON-NLS-1$ //$NON-NLS-2$ |
| "$ws$", 0, "$ws$".length()))) //$NON-NLS-1$ //$NON-NLS-2$ |
| return urlLocalizeFromBundleAndFragments(bundle, filenameWithinBundle); |
| try { |
| URL pvm = new URL(bundle.getEntry("/"), filenameWithinBundle); //$NON-NLS-1$ |
| pvm = verifyFound(Platform.asLocalURL(pvm)); |
| if (pvm != null) |
| return pvm; |
| } catch (IOException e) { |
| } |
| return findDev(bundle, filenameWithinBundle); |
| |
| } |
| |
| protected URL internalUrlLocalizeFromBundleOnly(Bundle bundle, String filenameWithinBundle) { |
| try { |
| URL pvm = bundle.getEntry(filenameWithinBundle); |
| if (pvm != null) |
| return Platform.asLocalURL(pvm); |
| } catch (IOException e) { |
| } |
| return findDev(bundle, filenameWithinBundle); |
| |
| } |
| |
| private URL verifyFound(URL pvm) throws IOException { |
| if (devMode) { |
| // Need to test if found in devmode. Otherwise we will just assume it is found. If not found on remote and moved to cache, an IOException would be thrown. |
| if (pvm != null) { |
| InputStream ios = null; |
| try { |
| ios = pvm.openStream(); |
| if (ios != null) |
| return pvm; // Found it, so return it. |
| } finally { |
| if (ios != null) |
| ios.close(); |
| } |
| } |
| } else |
| return pvm; |
| return null; |
| } |
| |
| /** |
| * @see ProxyPlugin#localizeFromBundle(bundle, String) |
| * |
| * This is just a helper to return a url instead. |
| * |
| * @param bundle |
| * @param filenameWithinBundle |
| * @return |
| * |
| * @since 1.0.0 |
| */ |
| public URL urlLocalizeFromBundleOnly(Bundle bundle, IPath filenameWithinBundle) { |
| return urlLocalizeFromBundleOnly(bundle, filenameWithinBundle.toString()); |
| } |
| |
| private URL findDev(Bundle bundle, String filenameWithinBundle) { |
| if (devMode) { |
| // Got this far and in dev mode means it wasn't found, so we'll try for development style. |
| // It is assumed that in dev mode, we are running with the IDE as local and any |
| // build outputs will be local so local file protocol will be returned |
| // from Platform.resolve(). We won't be running in dev mode with our entireplugin being in a jar, |
| // or on a separate system. |
| try { |
| URL pvm = bundle.getEntry(PROXYJARS); |
| if (pvm != null) { |
| InputStream ios = null; |
| try { |
| ios = pvm.openStream(); |
| Properties props = new Properties(); |
| props.load(ios); |
| String pathString = props.getProperty(filenameWithinBundle.toString()); |
| if (pathString != null) { |
| URL url = Platform.resolve(bundle.getEntry("/")); // It is assumed that if in debug mode, then this plugin is an imported plugin within the developement workspace. //$NON-NLS-1$ |
| if (url.getProtocol().equals("file")) { //$NON-NLS-1$ |
| File file = new File(url.getFile()).getParentFile(); // This gets us to workspace root of development workspace. |
| file = new File(file, pathString); |
| return file.toURL(); |
| } |
| } |
| } finally { |
| if (ios != null) |
| ios.close(); |
| } |
| } |
| } catch (IOException e) { |
| } |
| } |
| |
| return null; |
| |
| } |
| private URL[] findDevAllFromBundleAndFragments(Bundle bundle, String filenameWithinBundle) { |
| Bundle [] fragments = Platform.getFragments(bundle); |
| ArrayList urls = new ArrayList((fragments == null ? 0 : fragments.length) + 1); |
| URL url = findDev(bundle, filenameWithinBundle); |
| if (url != null) |
| urls.add(url); |
| if (fragments != null) { |
| for (int i = 0; i < fragments.length; i++) { |
| Bundle fragment = fragments[i]; |
| url = findDev(fragment, filenameWithinBundle); |
| if (url != null) |
| urls.add(url); |
| } |
| } |
| return (URL[]) urls.toArray(new URL[urls.size()]); |
| } |
| /** |
| * A helper to order the plugins into pre-req order. |
| * If A eventually depends on B, then B will be ahead of A in the |
| * list of plugins. (I.e. B is a pre-req somewhere of A). |
| * |
| * @param bundlesToOrder - Bundles of interest. The results will have these in thiee correct order. |
| * @return An array of the Bundlers in there order from no prereqs in set to the leaves. |
| * |
| * @since 1.0.0 |
| */ |
| public static Bundle[] orderPlugins(final Set bundlesToOrder) { |
| Map prereqsMap = new HashMap(bundlesToOrder.size()*3); |
| int ndx = bundlesToOrder.size(); |
| Bundle[] result = new Bundle[ndx]; |
| Map dependents = getDependentCounts(false, bundlesToOrder, prereqsMap); // We want the inactive ones too. That way have complete order. They can be ignored later if necessary. |
| // keep iterating until all have been visited. This will actually find them in reverse order from what we |
| // want, i.e. it will find the leaves first. So we will build result array in reverse order. |
| while (!dependents.isEmpty()) { |
| // loop over the dependents list. For each entry, if there are no dependents, visit |
| // the bundle and remove it from the list. Make a copy of the keys so we don't end up |
| // with concurrent accesses (since we are deleting the values as we go) |
| Iterator ib = dependents.entrySet().iterator(); |
| while (ib.hasNext()) { |
| Map.Entry entry = (Map.Entry) ib.next(); |
| Bundle bundle = (Bundle) entry.getKey() ; |
| int[] count = (int[]) entry.getValue(); |
| if (count != null && count[0] <= 0) { |
| if (bundlesToOrder.contains(bundle)) { |
| result[--ndx] = bundle; |
| if (ndx == 0) |
| return result; // We've ordered all that we care about. Anything left over is unimportant. |
| } |
| ib.remove(); |
| // decrement the dependent count for all of the prerequisites. |
| Bundle[] requires = getPrereqs(bundle, prereqsMap); |
| for (int j = 0; j < requires.length; j++) { |
| Bundle prereq = requires[j]; |
| int[] countPrereq = (int[]) dependents.get(prereq); |
| if (countPrereq != null) |
| --countPrereq[0]; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Get all of the prereqs for this bundle, all of the way down to the root. |
| * They will be in top-down depth-first order. There won't be duplicates. They will show up |
| * only once the first time they are found. |
| * |
| * @param bundle |
| * @return list of all pre-reqs. |
| * |
| * @since 1.0.0 |
| */ |
| public static List getAllPrereqs(Bundle bundle) { |
| List prereqs = new ArrayList(); |
| getAllPrereqs(bundle, prereqs, new HashMap()); |
| return prereqs; |
| } |
| |
| private static void getAllPrereqs(Bundle bundle, List prereqs, Map prereqsMap) { |
| Bundle[] prs = getPrereqs(bundle, prereqsMap); |
| for (int i = 0; i < prs.length; i++) { |
| Bundle pre = prs[i]; |
| if (prereqsMap.containsKey(pre)) |
| continue; // Already processed this one once. |
| prereqs.add(pre); // Add to the list of pre-reqs accumulated so far. |
| getAllPrereqs(pre, prereqs, prereqsMap); |
| } |
| } |
| |
| private static Bundle[] getPrereqs(Bundle bundle, Map prereqsMap) { |
| Bundle[] prereqs = (Bundle[]) prereqsMap.get(bundle); |
| if (prereqs == null) { |
| prereqs = getPrereqs(bundle); |
| prereqsMap.put(bundle, prereqs); |
| } |
| return prereqs; |
| } |
| |
| public static Bundle[] getPrereqs(Bundle bundle) { |
| Bundle[] l = (Bundle[]) pluginRequiredMap.get(bundle.getSymbolicName()); |
| if (l == null) { |
| BundleSpecification specs[] = Platform.getPlatformAdmin().getState(false).getBundle(bundle.getBundleId()).getRequiredBundles(); |
| ArrayList bundles = new ArrayList(specs.length); |
| for (int i = 0; i < specs.length; i++) { |
| Bundle b = Platform.getBundle(specs[i].getName()); |
| if (b != null) |
| bundles.add(b); |
| } |
| l = (Bundle[]) bundles.toArray(new Bundle[bundles.size()]); |
| pluginRequiredMap.put(bundle.getSymbolicName(), l); |
| } |
| return l; |
| } |
| |
| private static Map getDependentCounts(boolean activeOnly, Set startingSet, Map prereqsMap) { |
| Map dependents = new HashMap(startingSet.size()); |
| // build a table of all dependent counts. The table is keyed by descriptor and |
| // the value the integer number of dependent plugins. |
| List processNow = new ArrayList(startingSet); |
| List processNext = new ArrayList(processNow.size()); |
| if (!processNow.isEmpty()) { |
| // Go through the first time from the starting set to get an entry into the list. |
| // If there is an entry, then it won't be marked for processNext. Only new entries |
| // are added to processNext in the following loop. |
| int pnSize = processNow.size(); |
| for (int i = 0; i < pnSize; i++) { |
| Bundle bundle = (Bundle) processNow.get(i); |
| if (activeOnly && bundle.getState() != Bundle.ACTIVE) |
| continue; |
| // ensure there is an entry for this descriptor (otherwise it will not be visited) |
| int[] entry = (int[]) dependents.get(bundle); |
| if (entry == null) |
| dependents.put(bundle, new int[1]); |
| } |
| } |
| |
| // Now process the processNow to find the requireds, increment them, and add to processNext if never found before. |
| while (!processNow.isEmpty()) { |
| processNext.clear(); |
| int pnSize = processNow.size(); |
| for (int i = 0; i < pnSize; i++) { |
| Bundle bundle = (Bundle) processNow.get(i); |
| if (activeOnly && bundle.getState() != Bundle.ACTIVE) |
| continue; |
| Bundle[] requires = getPrereqs(bundle, prereqsMap); |
| for (int j = 0; j < requires.length; j++) { |
| Bundle prereq = requires[j]; |
| if (prereq == null || activeOnly |
| && bundle.getState() != Bundle.ACTIVE) |
| continue; |
| int[] entry = (int[]) dependents.get(prereq); |
| if (entry == null) { |
| dependents.put(prereq, new int[]{1}); |
| processNext.add(prereq); // Never processed before, so we add it to the next process loop. |
| } else |
| ++entry[0]; |
| } |
| } |
| |
| // Now swap the lists so that we processNext will be now and visa-versa. |
| List t = processNext; |
| processNext = processNow; |
| processNow = t; |
| } |
| return dependents; |
| } |
| |
| /** |
| * Add a shutdown listener |
| * @param listener |
| * |
| * @since 1.0.0 |
| */ |
| public void addProxyShutdownListener(IProxyPluginShutdownListener listener) { |
| if (shutdownListeners == null) |
| shutdownListeners = new ListenerList(); |
| shutdownListeners.add(listener); |
| } |
| |
| /** |
| * Remove a shutdown listener |
| * @param listener |
| * |
| * @since 1.0.0 |
| */ |
| public void removeProxyShutdownListener(IProxyPluginShutdownListener listener) { |
| if (shutdownListeners != null) |
| shutdownListeners.remove(listener); |
| } |
| |
| private ILaunchConfigurationListener launchListener = new ILaunchConfigurationListener() { |
| public void launchConfigurationAdded(ILaunchConfiguration configuration) { |
| try { |
| if (!configuration.isWorkingCopy() && IProxyConstants.ID_PROXY_LAUNCH_GROUP.equals(configuration.getCategory())) |
| startCleanupJob(); |
| } catch (Exception e) { |
| } |
| } |
| |
| public void launchConfigurationChanged(ILaunchConfiguration configuration) { |
| try { |
| if (!configuration.isWorkingCopy() && IProxyConstants.ID_PROXY_LAUNCH_GROUP.equals(configuration.getCategory())) |
| startCleanupJob(); |
| } catch (Exception e) { |
| } |
| } |
| |
| public void launchConfigurationRemoved(ILaunchConfiguration configuration) { |
| try { |
| // On delete you can't tell the category or anything because all of that info has already removed. |
| if (!configuration.isWorkingCopy()) |
| startCleanupJob(); |
| } catch (Exception e) { |
| } |
| } |
| }; |
| |
| private Job cleanupJob = new Job(ProxyMessages.ProxyPlugin_CleanupDefaultProxyLaunchConfigurations) { |
| { |
| setSystem(true); // So it doesn't show up in progress monitor. No need to interrupt user. |
| setPriority(Job.SHORT); // A quick running job. |
| } |
| protected IStatus run(IProgressMonitor monitor) { |
| synchronized (this) { |
| if (monitor.isCanceled()) |
| return Status.CANCEL_STATUS; |
| } |
| // all we want to do is find out if any launch configurations (from proxy launch group) exist for |
| // a project. If they don't, then unset the project's property. If they do, and the property is not |
| // set, then set it to NOT_SET to indicate not set, but there are some configs for it. |
| // We just gather the project names that have launch configurations. |
| try { |
| Set projectNames = new HashSet(); |
| ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(); |
| for (int i = 0; i < configs.length; i++) { |
| if (IProxyConstants.ID_PROXY_LAUNCH_GROUP.equals(configs[i].getCategory()) |
| && (ProxyLaunchSupport.ATTR_PRIVATE == null || !configs[i].getAttribute(ProxyLaunchSupport.ATTR_PRIVATE, false))) |
| projectNames.add(configs[i].getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, "")); //$NON-NLS-1$ |
| } |
| |
| IJavaModel model = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()); |
| IJavaElement[] children = model.getChildren(); |
| int cancelCount = 10; |
| for (int j = 0; j < children.length; j++) { |
| if (children[j].getElementType() == IJavaElement.JAVA_PROJECT) { |
| if (--cancelCount <= 0) |
| synchronized (this) { |
| cancelCount = 10; // Rest for next set of ten. |
| // Checking on every 10 projects because they may be many projects, while only few configs. |
| // This way it will stop sooner. |
| if (monitor.isCanceled()) |
| return Status.CANCEL_STATUS; |
| } |
| IProject p = ((IJavaProject) children[j]).getProject(); |
| if (projectNames.contains(p.getName())) { |
| // This project has a launch config. If it has a setting, then do nothing, else need to put on not set. |
| if (p.getPersistentProperty(ProxyPlugin.PROPERTY_LAUNCH_CONFIGURATION) == null) |
| p.getProject().setPersistentProperty( |
| ProxyPlugin.PROPERTY_LAUNCH_CONFIGURATION, |
| ProxyLaunchSupport.NOT_SET); |
| } else { |
| // This project has no launch configs. Remove any setting if it exists. |
| p.setPersistentProperty(ProxyPlugin.PROPERTY_LAUNCH_CONFIGURATION, (String) null); |
| } |
| } |
| } |
| return Status.OK_STATUS; |
| } catch (CoreException e) { |
| return e.getStatus(); |
| } |
| } |
| }; |
| |
| private void startCleanupJob() { |
| cleanupJob.cancel(); // Stop what we are doing. |
| cleanupJob.schedule(1000l); // Schedule to start in one second. |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) |
| */ |
| public void start(final BundleContext context) throws Exception { |
| super.start(context); |
| DebugPlugin.getDefault().getLaunchManager().addLaunchConfigurationListener(launchListener); |
| context.addBundleListener(new BundleListener() { |
| public void bundleChanged(BundleEvent event) { |
| if (event.getBundle() != ProxyPlugin.this.getBundle()) |
| return; // Not of interest to us. |
| switch (event.getType()) { |
| case BundleEvent.STARTED: |
| context.removeBundleListener(this); // Since we don't care anymore |
| startCleanupJob(); |
| break; |
| case BundleEvent.STOPPED: |
| case BundleEvent.UNINSTALLED: |
| case BundleEvent.UNRESOLVED: |
| context.removeBundleListener(this); // We stopped before we started, so remove ourselves. |
| break; |
| } |
| } |
| }); |
| getPluginPreferences().setDefault(PREFERENCES_VM_NOVERIFY_KEY, true); |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) |
| */ |
| public void stop(BundleContext context) throws Exception { |
| // Handle case where debug plugin shuts down before we do since order not guarenteed. |
| if (DebugPlugin.getDefault() != null) |
| DebugPlugin.getDefault().getLaunchManager().removeLaunchConfigurationListener(launchListener); |
| cleanupJob.cancel(); // Stop what we are doing. |
| if (shutdownListeners != null) { |
| Object[] listeners = shutdownListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| ((IProxyPluginShutdownListener) listeners[i]).shutdown(); |
| } |
| } |
| super.stop(context); |
| } |
| |
| public static final String PI_CONFIGURATION_CONTRIBUTION_EXTENSION_POINT = "org.eclipse.jem.proxy.contributors"; //$NON-NLS-1$ |
| public static final String PI_EXTENSION_REGISTRATION_EXTENSION_POINT = "org.eclipse.jem.proxy.extensions"; //$NON-NLS-1$ |
| public static final String PI_CONTAINER = "container"; //$NON-NLS-1$ |
| public static final String PI_PLUGIN = "plugin"; //$NON-NLS-1$ |
| public static final String PI_CLASS = "class"; //$NON-NLS-1$ |
| public static final String PI_REGISTRY_TYPE = "registryType"; //$NON-NLS-1$ |
| public static final Map pluginRequiredMap = new HashMap(50); |
| |
| /* |
| * Map of container id's to their ordered array of contribution config elements. |
| */ |
| protected Map containerToContributions = null; |
| /* |
| * Map of plugin id's to their ordered array of contribution config elements. |
| */ |
| protected Map pluginToContributions = null; |
| |
| /* |
| * Map of container id's to their ordered array of extension config elements. |
| */ |
| protected Map containerToExtensions = null; |
| /* |
| * Map of plugin id's to their ordered array of contribution config elements. |
| */ |
| protected Map pluginToExtension = null; |
| |
| |
| /** |
| * These are public only so that jem.ui can access this constant. Not meant to be accessed by others. |
| */ |
| public static final QualifiedName PROPERTY_LAUNCH_CONFIGURATION = new QualifiedName("org.eclipse.jem.proxy", "proxyLaunchConfiguration"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| /** |
| * Return the plugin ordered array of configuration elements for the given container, or <code>null</code> if not contributed. |
| * |
| * @param containerid |
| * @return Array of configuration elements or <code>null</code> if this container has no contributions. |
| * |
| * @since 1.0.0 |
| */ |
| public synchronized IConfigurationElement[] getContainerConfigurations(String containerid) { |
| if (containerToContributions == null) |
| processProxyContributionExtensionPoint(); |
| return (IConfigurationElement[]) containerToContributions.get(containerid); |
| } |
| |
| /** |
| * Return the plugin ordered array of configuration elements for the given plugin, or <code>null</code> if not contributed. |
| * |
| * @param pluginid |
| * @return Array of configuration elements or <code>null</code> if this plugin has no contributions. |
| * |
| * @since 1.0.0 |
| */ |
| public synchronized IConfigurationElement[] getPluginConfigurations(String pluginid) { |
| if (pluginToContributions == null) |
| processProxyContributionExtensionPoint(); |
| return (IConfigurationElement[]) pluginToContributions.get(pluginid); |
| } |
| |
| /** |
| * Return the plugin ordered array of configuration elements for the given container, or <code>null</code> if not contributed. |
| * |
| * @param containerid |
| * @return Array of extension registration elements or <code>null</code> if this container has no contributions. |
| * |
| * @since 1.0.0 |
| */ |
| public synchronized IConfigurationElement[] getContainerExtensions(String containerid) { |
| if (containerToExtensions == null) |
| processProxyExtensionExtensionPoint(); |
| return (IConfigurationElement[]) containerToExtensions.get(containerid); |
| } |
| |
| /** |
| * Return the plugin ordered array of configuration elements for the given plugin, or <code>null</code> if not contributed. |
| * |
| * @param pluginid |
| * @return Array of configuration elements or <code>null</code> if this plugin has no contributions. |
| * |
| * @since 1.0.0 |
| */ |
| public synchronized IConfigurationElement[] getPluginExtensions(String pluginid) { |
| if (pluginToExtension == null) |
| processProxyExtensionExtensionPoint(); |
| return (IConfigurationElement[]) pluginToExtension.get(pluginid); |
| } |
| |
| protected synchronized void processProxyContributionExtensionPoint() { |
| ContributorExtensionPointInfo info = processContributionExtensionPoint(PI_CONFIGURATION_CONTRIBUTION_EXTENSION_POINT); |
| containerToContributions = info.containerToContributions; |
| pluginToContributions = info.pluginToContributions; |
| } |
| |
| protected synchronized void processProxyExtensionExtensionPoint() { |
| ContributorExtensionPointInfo info = processContributionExtensionPoint(PI_EXTENSION_REGISTRATION_EXTENSION_POINT); |
| containerToExtensions = info.containerToContributions; |
| pluginToExtension = info.pluginToContributions; |
| } |
| |
| /** |
| * Result form processContributionExtensionPoint. |
| * |
| * @see ProxyPlugin#processContributionExtensionPoint(String) |
| * @since 1.0.0 |
| */ |
| public static class ContributorExtensionPointInfo { |
| /** |
| * Map of container ids (String) to contributions (IConfigurationElement[]) that was found with that id. For each container, |
| * the contributions will be listed in plugin prereq order. |
| */ |
| public Map containerToContributions; |
| |
| /** |
| * Map of plugin ids (String) to contributions (IConfigurationElement[]) that was found with that id. For each plugin, |
| * the contributions will be listed in plugin prereq order. |
| */ |
| public Map pluginToContributions; |
| } |
| |
| /** |
| * Process the extension point looking contributors. It will find entries that have the "container" or "plugin" attributes |
| * set on them. |
| * |
| * @param extensionPoint fully-qualified extension point id, including plugin id of the extension point. |
| * @return the contributor info record. |
| * |
| * @since 1.0.0 |
| */ |
| public static ContributorExtensionPointInfo processContributionExtensionPoint(String extensionPoint) { |
| // We are processing this once because it is accessed often (once per vm per project). |
| // This can add up so we get it together once here. |
| IExtensionPoint extp = Platform.getExtensionRegistry().getExtensionPoint(extensionPoint); |
| ContributorExtensionPointInfo result = new ContributorExtensionPointInfo(); |
| if (extp == null) { |
| result.containerToContributions = Collections.EMPTY_MAP; |
| result.pluginToContributions = Collections.EMPTY_MAP; |
| return result; |
| } |
| |
| IExtension[] extensions = extp.getExtensions(); |
| // Need to be in plugin order so that first ones processed have no dependencies on others. |
| HashMap bundlesToExtensions = new HashMap(extensions.length); |
| for (int i = 0; i < extensions.length; i++) { |
| Bundle bundle = Platform.getBundle(extensions[i].getNamespace()); |
| IExtension[] ext = (IExtension[]) bundlesToExtensions.get(bundle); |
| if (ext == null) |
| bundlesToExtensions.put(bundle, new IExtension[] {extensions[i]}); |
| else { |
| // More than one extension defined in this plugin. |
| IExtension[] newExt = new IExtension[ext.length + 1]; |
| System.arraycopy(ext, 0, newExt, 0, ext.length); |
| newExt[newExt.length-1] = extensions[i]; |
| bundlesToExtensions.put(bundle, newExt); |
| } |
| } |
| |
| // Now order them so we process in required order. |
| // If it is the first time, we are about to find out many inter-dependencies |
| // notify the cache on a start/end of a transaction so that updates (if new |
| // dependencies) are updated only once |
| Bundle[] ordered = ProxyPlugin.orderPlugins(bundlesToExtensions.keySet()); |
| result.containerToContributions = new HashMap(ordered.length); |
| result.pluginToContributions = new HashMap(ordered.length); |
| for (int i = 0; i < ordered.length; i++) { |
| IExtension[] exts = (IExtension[]) bundlesToExtensions.get(ordered[i]); |
| for (int j = 0; j < exts.length; j++) { |
| IConfigurationElement[] configs = exts[j].getConfigurationElements(); |
| // Technically we expect the config elements to have a name of "contributor", but since that |
| // is all that can be there, we will ignore it. The content is what is important. |
| for (int k = 0; k < configs.length; k++) { |
| String container = configs[k].getAttributeAsIs(PI_CONTAINER); |
| if (container != null) { |
| List contributions = (List) result.containerToContributions.get(container); |
| if (contributions == null) { |
| contributions = new ArrayList(1); |
| result.containerToContributions.put(container, contributions); |
| } |
| contributions.add(configs[k]); |
| } |
| String plugin = configs[k].getAttributeAsIs(PI_PLUGIN); |
| if (plugin != null) { |
| List contributions = (List) result.pluginToContributions.get(plugin); |
| if (contributions == null) { |
| contributions = new ArrayList(1); |
| result.pluginToContributions.put(plugin, contributions); |
| } |
| contributions.add(configs[k]); |
| } |
| } |
| } |
| } |
| |
| // Now go through and turn all of the contribution lists into arrays. |
| for (Iterator iter = result.containerToContributions.entrySet().iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| entry.setValue(((List) entry.getValue()).toArray(new IConfigurationElement[((List) entry.getValue()).size()])); |
| } |
| for (Iterator iter = result.pluginToContributions.entrySet().iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| entry.setValue(((List) entry.getValue()).toArray(new IConfigurationElement[((List) entry.getValue()).size()])); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * For the given java project, return the maps of container paths and plugins found. The keys will be of type as specified for the parms |
| * while the value will be Boolean, true if it was visible, and false if it wasn't. |
| * For example if <code>/SWT_CONTAINER/subpath1</code> is found in the projects path (or from required projects), then |
| * the container id will be added to the map. They come from the raw classpath entries of the projects. |
| * |
| * @param jproject |
| * @param containerIds This map will be filled in with container ids as keys (type is <code>java.lang.String</code>) that are found in the projects build path. The value will be a Boolean, true if this container id was visible to the project (i.e. was in the project or was exported from a required project). |
| * @param containers This map will be filled in with classpath containers as keys found in the projects build path. The value will be a Boolean as in container ids map. |
| * @param pluginIds This map will be filled in with plugin ids as keys (type is <code>java.lang.String</code>) that are found in the projects build path. The value will be a Boolean as in container ids map. |
| * @param projects This map will be filled in with project paths (except the top project) as keys (type is <code>org.eclipse.core.runtime.IPath</code>) that are found in the projects build path. The value will be a Boolean as in container ids map. |
| * |
| * @since 1.0.0 |
| */ |
| public void getIDsFound(IJavaProject jproject, Map containerIds, Map containers, Map pluginIds, Map projects) throws JavaModelException { |
| IPath projectPath = jproject.getProject().getFullPath(); |
| projects.put(projectPath, Boolean.TRUE); |
| expandProject(projectPath, containerIds, containers, pluginIds, projects, true, true); |
| projects.remove(projectPath); // Don't need to include itself now, was needed for testing so if ciruclar we don't get into a loop. |
| } |
| |
| /* |
| * The passed in visible flag tells if this project is visible and its contents are visible if they are exported. |
| * Only exception is if first is true, then all contents are visible to the top level project. |
| */ |
| private void expandProject(IPath projectPath, Map containerIds, Map containers, Map pluginIds, Map projects, boolean visible, boolean first) throws JavaModelException { |
| IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(projectPath.lastSegment()); |
| if (res == null) |
| return; // Not exist so don't delve into it. |
| IJavaProject project = (IJavaProject)JavaCore.create(res); |
| if (project == null || !project.exists() || !project.getProject().isOpen()) |
| return; // Not exist as a java project or not open, so don't delve into it. |
| |
| IClasspathEntry[] entries = project.getRawClasspath(); |
| for (int i = 0; i < entries.length; i++) { |
| IClasspathEntry entry = entries[i]; |
| Boolean currentFlag = null; // Current setting value. |
| boolean newFlag; // The new setting value. |
| switch (entry.getEntryKind()) { |
| case IClasspathEntry.CPE_PROJECT: |
| // Force true if already true, or this is the first project, or this project is visible and the entry is exported. These override a previous false. |
| currentFlag = (Boolean) projects.get(entry.getPath()); |
| newFlag = (currentFlag != null && currentFlag.booleanValue()) || first || (visible && entry.isExported()); |
| if (currentFlag == null || currentFlag.booleanValue() != newFlag) |
| projects.put(entry.getPath(), newFlag ? Boolean.TRUE : Boolean.FALSE ); |
| if (currentFlag == null) |
| expandProject(entry.getPath(), containerIds, containers, pluginIds, projects, visible && entry.isExported(), false); |
| break; |
| case IClasspathEntry.CPE_CONTAINER: |
| if (!first && "org.eclipse.jdt.launching.JRE_CONTAINER".equals(entry.getPath().segment(0))) //$NON-NLS-1$ |
| break; // The first project determines the JRE, so any subsequent ones can be ignored. |
| currentFlag = (Boolean) containerIds.get(entry.getPath().segment(0)); |
| newFlag = (currentFlag != null && currentFlag.booleanValue()) || first || (visible && entry.isExported()); |
| if (currentFlag == null || currentFlag.booleanValue() != newFlag) |
| containerIds.put(entry.getPath().segment(0), newFlag ? Boolean.TRUE : Boolean.FALSE ); |
| |
| IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project); |
| // Force true if already true, or this is the first project, or this project is visible and the entry is exported. These override a previous false. |
| currentFlag = (Boolean) containers.get(container); |
| newFlag = (currentFlag != null && currentFlag.booleanValue()) || first || (visible && entry.isExported()); |
| if (currentFlag == null || currentFlag.booleanValue() != newFlag) |
| containers.put(container, newFlag ? Boolean.TRUE : Boolean.FALSE ); |
| break; |
| case IClasspathEntry.CPE_VARIABLE: |
| // We only care about JRE_LIB. If we have that, then we will treat it as JRE_CONTAINER. Only |
| // care about first project too, because the first project is the one that determines the JRE type. |
| if (first && "JRE_LIB".equals(entry.getPath().segment(0))) { //$NON-NLS-1$ |
| currentFlag = (Boolean) containerIds.get("org.eclipse.jdt.launching.JRE_CONTAINER"); //$NON-NLS-1$ |
| if (currentFlag == null || !currentFlag.booleanValue()) |
| containerIds.put("org.eclipse.jdt.launching.JRE_CONTAINER", Boolean.TRUE); //$NON-NLS-1$ |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| findPlugins(pluginIds, visible, first, project); |
| } |
| |
| /** |
| * Find the plugins that the given project references, either directly or indirectly. |
| * <p> |
| * The map will be of plugin ids to a Boolean. If the boolean is <code>BooleanTRUE</code>, |
| * then the plugin is visible to the given project. the visible and first flags |
| * will modify this. If first is true, then all direct plugins will be visible, |
| * else only exported plugins will be visible. If visible is false and first is false, then it doesn't matter, all of the |
| * plugins will not be visible. |
| * <p> |
| * Visible means that classes in the plugin can be referenced directly from code. Not visible |
| * means that they can only be referenced from some other plugin in the list. In other words, |
| * visible ones can be directly referenced, but invisible ones can only be referenced from |
| * plugins that can see it. |
| * <p> |
| * For most uses, first and visible should be true. Then it will treat the project as the toplevel |
| * project and will return true for those that are visible to it, either directly or indirectly. |
| * These flags were added for more special cases where may be calling on a project that is deeper |
| * down in the classpath were visibilty has already been decided. |
| * <p> |
| * Note: PDE must be installed for this to return anything, otherwise it will leave |
| * the map alone. |
| * |
| * @param pluginIds map of pluginIds->Boolean(TRUE is visible) |
| * @param visible <code>true</code> means this project is visible, so any plugins visible to it will be visible, else none will be visible. |
| * @param first <code>true</code> if this is the top project of interest. This means that all plugins within the project are visible. Else only exported projects will be visible. |
| * @param project project to start looking from |
| * |
| * @since 1.0.2 |
| */ |
| public void findPlugins(Map pluginIds, boolean visible, boolean first, IJavaProject project) { |
| try { |
| // To prevent unnecessary loading of the PDE plugin, find the plugins only if this project is a PDE plugin project. |
| if (isPDEProject(project)) { |
| IPDEProcessForPlugin pdeprocess = getPDEProcessForPlugin(); |
| if (pdeprocess != null) |
| pdeprocess.findPlugins(project, pluginIds, visible, first); // expand the plugins for this project, if any. |
| } |
| } catch (CoreException e) { |
| } |
| } |
| |
| /** |
| * |
| * @param project |
| * |
| * @return true if this is a Plugin project or false if not |
| * @throws CoreException |
| * |
| * @since 1.1.0 |
| */ |
| public static boolean isPDEProject(IJavaProject project) throws CoreException { |
| return project.getProject().hasNature(PDE_NATURE_ID); |
| } |
| |
| |
| /* |
| * Interface for processing Plugins. Used when PDE plugin is present in the installation. |
| * |
| * @since 1.0.2 |
| */ |
| interface IPDEProcessForPlugin { |
| |
| /* |
| * Go through the project and find all of the plugins it references, either directly or through |
| * the referenced plugins, and mark them as visible or not. |
| */ |
| public abstract void findPlugins(IJavaProject project, Map pluginIds, boolean visible, boolean first); |
| } |
| |
| /* |
| * Try to get the pde process for plugin. If already tried once and not found, then forget it. |
| * <package-protected> because PDEContributeClasspath needs it too. |
| */ |
| private IPDEProcessForPlugin pdeProcessForPlugin; |
| private boolean triedPDEProcess; |
| IPDEProcessForPlugin getPDEProcessForPlugin() { |
| if (!triedPDEProcess) { |
| triedPDEProcess = true; |
| if (Platform.getBundle("org.eclipse.pde.core") != null) { //$NON-NLS-1$ |
| try { |
| Class classPDEProcess = Class.forName("org.eclipse.jem.internal.proxy.core.PDEProcessForPlugin"); //$NON-NLS-1$ |
| pdeProcessForPlugin = (IPDEProcessForPlugin) classPDEProcess.newInstance(); |
| } catch (ClassNotFoundException e) { |
| // Not found, do nothing. |
| } catch (InstantiationException e) { |
| getLogger().log(e, Level.WARNING); |
| } catch (IllegalAccessException e) { |
| getLogger().log(e, Level.WARNING); |
| } |
| } |
| } |
| return pdeProcessForPlugin; |
| } |
| |
| /** |
| * This tries to find a jar in the bundle specified, and the attached source using the |
| * PDE source location extension point. The jar must exist for source to be attachable. |
| * The source must be in the standard PDE source plugin. I.e. it must be in a directory |
| * of the name "bundlename_bundleversion", and in the same path from there as in the |
| * jar, plus the name must be "jarnamesrc.zip". |
| * <p> |
| * The returned URL's will not be Platform.resolve(). They will be in form returned from |
| * Platform.find(). |
| * |
| * @param bundle bundle to search, will search fragments too. |
| * @param filepath filepath from the root of the bundle/fragment where the jar will be found. |
| * @return two URL's. [0] is the URL to the jar, <code>null</code> if not found, [2] is the URL to the source zip, <code>null</code> if not found. |
| * |
| * @since 1.0.0 |
| */ |
| public URL[] findPluginJarAndAttachedSource(Bundle bundle, IPath filepath) { |
| // This is a bit kludgy, but the algorithm is to find the file first, and then get the root url of the bundle/fragment |
| // that matches the found file. This will be used to calculate the name of the directory under the source. From there |
| // all of the source extensions will be searched for the source zip file. |
| // This is assuming that find returns a url where the file part of the url is a standard path and doesn't have |
| // things like special chars to indicate within a jar. That would appear when it is resolved, but I think that the |
| // unresolved ones from find are typically "jarbundle://nnn/path" or something like that. This is a gray area. |
| URL jarURL = Platform.find(bundle, filepath); |
| if (jarURL == null) |
| return new URL[2]; |
| |
| // Found it, so let's try to find which bundle/fragment it was found in. |
| String jarString = jarURL.toExternalForm(); |
| // First the bundle itself. |
| String installLoc = bundle.getEntry("/").toExternalForm(); //$NON-NLS-1$ |
| URL sourceURL = null; |
| if (jarString.startsWith(installLoc)) |
| sourceURL = getSrcFrom(bundle, installLoc, jarString); |
| else { |
| // Now look in the fragments. |
| Bundle[] frags = Platform.getFragments(bundle); |
| for (int i = 0; i < frags.length; i++) { |
| installLoc = frags[i].getEntry("/").toExternalForm(); //$NON-NLS-1$ |
| if (jarString.startsWith(installLoc)) { |
| sourceURL = getSrcFrom(frags[i], installLoc, jarString); |
| break; |
| } |
| } |
| } |
| return new URL[] {jarURL, sourceURL}; |
| } |
| |
| private URL getSrcFrom(Bundle bundle, String installLoc, String jarString) { |
| // format of path in a PDE source plugin is (under the "src" directory from the extension point), |
| // "bundlename_bundleversion/pathOfJar/jarnamesrc.zip". However there is no way to know |
| // which extension has the source in it, so we need to search them all. |
| |
| IPath srcPath = new Path(bundle.getSymbolicName()+"_"+ (String) bundle.getHeaders("").get(Constants.BUNDLE_VERSION)); //$NON-NLS-1$ //$NON-NLS-2$ $NON-NLS-2$ |
| srcPath = srcPath.append(new Path(jarString.substring(installLoc.length()))); |
| if (srcPath.segmentCount() < 2) |
| return null; // Something is not right. No jar name. |
| srcPath = srcPath.removeFileExtension(); // Remove the .jar. |
| String jarName = srcPath.lastSegment(); // This should be the jar name. |
| srcPath = srcPath.removeLastSegments(1).append(jarName+"src.zip"); //$NON-NLS-1$ |
| |
| // Now look through all of the src extensions. Can't tell if the extension is from a fragment or a bundle, so we need to |
| // use Platform.find() to look in the bundle and fragment. So we may get a dup search if there is a fragment source |
| // (for example platform source and win32 platform source (which is a fragment of platform source). |
| IConfigurationElement[] ces = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.pde.core.source"); //$NON-NLS-1$ |
| for (int i = 0; i < ces.length; i++) { |
| IPath srcsrch = new Path(ces[i].getAttributeAsIs("path")).append(srcPath); //$NON-NLS-1$ |
| Bundle srcBundle = Platform.getBundle(ces[i].getDeclaringExtension().getNamespace()); |
| URL srcUrl = Platform.find(srcBundle, srcsrch); |
| if (srcUrl != null) { |
| return srcUrl; |
| } |
| } |
| return null; |
| } |
| } |