Imagine wanting to use a particular plug-in with Eclipse, and you do everything necessary to include it in your plug-in manifest file and declare it as a dependency. But the system does not load the plug-in, and you are stuck without making any further progress in your software development.
Sound familiar? If so, you may have also spent time and effort going through many plugin.xml files to pinpoint the particular plug-in that Eclipse could not load. You may also have tried using the Plug-in Dependencies view that comes with the Eclipse PDE project, only to find out that its job is to list just the successfully loaded plug-ins. Unfortunately, your problematic plug-in probably does not fall into this category of plug-ins successfully loaded.
What can you do to pinpoint that particular plug-in that Eclipse could not find or load? Instead of manually trying to go through each plugin.xml file, consider automating your search. To automate your search, you need to know how Eclipse keeps its plug-ins and how it finds the link to various other plug-ins that are somewhere else on the disk. Based on this knowledge, you may want to write your own code to create a plug-in dependency walker or just use my general-purpose Dependency Walker plug-in. The Download section of this article contains the source code.
Getting started: Understanding plug-in dependency and Eclipse plug-in links
Eclipse plug-ins are software modules providing some functionality that other plug-ins can further use. If plug-in A requires plug-in B for its functioning, A is said to be dependent on B. This dependency also means that unless plug-in B is successfully loaded, plug-in A will not work. At times, plug-in B may also depend on plug-in C, plug-in D, plug-in E, ad nauseam -- and each of these plug-ins may further depend on others. Such a dependency chain can easily run into hundreds of linked plug-ins. No doubt, then, that if any plug-in in this chain fails to load successfully, the dependent plug-ins may have problems.
A plug-in manifest file named plugin.xml describes each plug-in. This XML file has a section to declare dependencies on or requirements of other plug-ins. In Listing 1, the plugin.xml file section that declares dependencies appears in bold.
Listing 1. plugin.xml file
<?xml version="1.0" encoding="UTF-8" ?> <?eclipse version="3.0"?> <plugin id="org.eclipse.draw2d" name="Draw2d" version="3.0.0" provider-name="Eclipse.org"> <runtime> <library name="draw2d.jar"> <export name="*" /> <packages prefixes="org.eclipse.draw2d" /> </library> </runtime> <requires> <import plugin="org.eclipse.swt" export="true" /> <import plugin="org.eclipse.core.runtime" /> </requires> </plugin> |
Notice the <import plugin="plugin id"/> declarations embedded inside the <requires> </requires> section. The sample in Listing 1 shows that the plug-in ID org.eclipse.draw2d depends on plug-ins with the IDs org.eclipse.swt and org.eclipse.core.runtime.
When you develop software using the Java™ technology platform perspective in Eclipse, the system actually compiles your code against your preferred target platform. You can specify the target platform location at Window > Preferences > Plug-in Development > Target Platform. The target platform has its own copy of Eclipse at <targetPlatform>\eclipse. To resolve the dependencies for your code, look for availability of required plug-ins in two areas:
- The Eclipse plug-ins under the <targetPlatform>\eclipse\plugins folder
- The linked plug-ins pointed out by .link files inside the <targetPlatform>\eclipse\links folder
Programmers usually refer to the second area as the links folder. The links folder contains zero or more files, usually ending in a ".link" extension. These files contain the link information leading to the location on the disk where you can find the linked plug-ins.
Each .link file has a key-value pair that has a path=location format. (For example, the links folder C:\eclipse\links may have any number of .link files, and one of these files may be named com.ibm.indiver.dependencywalker.link. The single line contained inside this file may look like path=c:\myPlugins\dependencyWalker). This .link file instructs Eclipse to go to the specified location and look for more plug-ins in the \eclipse\plugins folder available there.
Creating your own Eclipse plug-in dependency walker
Writing a dependency walker is basically a two-part process: list all the plug-ins and list the dependencies of a user-selected plug-in.
The first part deals with locating each and every plug-in physically present under an Eclipse system and providing the list of all plug-ins in some simple user interface (UI) -- for example, a table -- to the end user. This UI should also provide some way for users to select a plug-in whose dependency chain they want to observe.
The second part deals with parsing the plugin.xml file of the user-selected plug-in and looking for the <import plugin="plugin id"/> declarations embedded inside the <requires> </requires> section of that plugin.xml file. This effort obviously requires a recursive search into each and every plug-in manifest file to follow the complete chain of dependent plug-ins. A tree view is one of the best-suited UIs to describe the parent-sibling-child kind of relationships plug-ins have when they depend on other plug-ins. You should also visually denote whether the Eclipse plug-in registry actually loaded a physically present plug-in.
Part 1: Listing all the plug-ins in the Eclipse system
Armed with the following information, you can go about writing code to list all the plug-ins physically present somewhere on the disk:
- Plug-ins are located primarily in the <targetPlatform>\eclipse\plugins folder
- Plug-ins may also be found in multiple other <someLinkedPath>\eclipse\plugins folders.
- You can obtain the path to every <someLinkedPath> from the .link files in the <targetPlatform>\eclipse\links folder.
Here is the step-by-step process for listing all the plug-ins in an Eclipse system:
- Find the location of the target platform.
- Prepare the path of the links folder. The links folder is in the \eclipse folder.
- Get the list of files in the \eclipse\links folder. Refer to the
Utilities.getLinkedPaths()function in the source code. - Look into each .link file and get the path of the linked Eclipse folders.
- Prepare a list of all plug-in root folders (that is, the <targetPlatform>\eclipse\plugins folder and all possible <someLinkedPath>\eclipse\plugins folders).
- For each plug-in root folder, go to each plug-in directory and get the path of the plugin.xml file.
- Parse the plugin.xml file to get the plug-in ID and plug-in version, and store the information in a data structure.
- Go back to Step 6 to continue with the next plug-in directory.
Listing 2. Preparing a list of all plug-ins physically present under an Eclipse system
/**
*
* @return returns a Vector containing PluginData objects.
* Each PluginData object represents a Plugin found under any of the following
* plugin directories
* a. the targetPlatformLocation\eclipse\plugins directory,
* b. other plugin directories as specified by *.link files under
* targetPlatform\eclipse\links directory
**/
public static Vector getPluginsInTargetPlatform(){
/**
//step1: Get path of target platform.
//step2: Prepare path of links folder.
//step3: Get list of files in links folder.
//step4: Parse each link file and get the path of linked Eclipse folder.
//step5: Prepare a list of all plugin root folders
// (Eclipse plugins and linked Eclipse plugins).
//step6: 6a. For each plugin root folder,
// 6b. go to each plugin directory and get path of plugin.xml.
//step7: Parse the plugin.xml file to get plugin id, plugin version,
// and store in vectors, lists, etc.
//step8: Go back to step 6 to continue with next plugin directory.
**/
//step1: Get path of target platform.
//Fall back to Eclipse install location if targetplatform in not set.
URL platFormURL = Platform.getInstallLocation().getURL();
Location location = Platform.getInstallLocation();
IPath eclipsePath = null ;
//Get path of target platform against which the users of this tool
//will compile their code.
IPath targetPlatFormLocation = new Path(getTargetPlatformPath(true));
if(_useTargetPlatform == false)
eclipsePath = new Path(platFormURL.getPath());
else
eclipsePath = targetPlatFormLocation;
showMessage("Considering target platform to be: " +
eclipsePath.toString());
//step2: Prepare path of links folder.
//step3: Get list of files in links folder.
//step4: Parse each link file and get the path of linked Eclipse folder.
IPath linksPath = new Path( eclipsePath.toString() ).append("/links");
String linkedPaths[] = getLinkedPaths(linksPath.toString());
int linkedPathLength = 0;
if(null != linkedPaths){
linkedPathLength = linkedPaths.length;
}
//step5: Prepare a list of all plugin root folders
// (Eclipse plugins and linked Eclipse plugins).
IPath eclipsePluginRootFolders[] = new IPath[linkedPathLength + 1];
eclipsePluginRootFolders[0] =
new Path( eclipsePath.toString() ).append("/plugins");
if(null != linkedPaths){
for(int i=0; i<linkedPaths.length; i++){
eclipsePluginRootFolders[i+1] =
new Path(linkedPaths[i]).append("/eclipse/plugins");
}
}
//step6: 6a. For each plugin root folder,
// 6b. go to each plugin directory and get path of plugin.xml.
//step7: Parse the plugin.xml file to get plugin id, plugin version,
// and store in vectors, lists, etc.
Vector vectorsInThisVector = new Vector();
for(int i=0; i<eclipsePluginRootFolders.length; i++){
System.out.println("\n========plugin IDs and Versions in " +
eclipsePluginRootFolders[i] + "========");
Vector pluginDataObjs =
getPluginDataForAllPlugins(
eclipsePluginRootFolders[i].toString());
vectorsInThisVector.add(pluginDataObjs);
System.out.println(pluginDataObjs);
System.out.println("\n===========|||=== end ===|||===========");
}
Vector pluginData = new Vector();
Iterator outerIterator = vectorsInThisVector.iterator();
while(outerIterator.hasNext()){
Vector pluginDataObjs = (Vector)outerIterator.next();
Iterator innerIterator = pluginDataObjs.iterator();
while(innerIterator.hasNext()){
PluginData pd = (PluginData)innerIterator.next();
String pluginIdKey = pd.getPluginID();
String versionValue = pd.getPluginVersion();
String pluginPath = pd.getPluginLocation();
pluginData.add(pd);
}
}
int breakpoint=0;
return pluginData;
}
|
Once you have all the plug-ins, you can display the plug-in ID, version, location, and more, in a Standard Widget Toolkit (SWT) table to make the information presentable. You can also optionally write code to sort the columns on plug-in ID like in the sample code. You should indicate in one of the columns the number of plug-ins found. The results should look something like this:
Figure 1. All Plug-ins in Target-Platform view
Part 2: Recursive search on plugin.xml files to walk through the dependency chain
Once users select a plug-in for which they want to observe the dependency chain, you have to parse the plugin.xml file of the user-selected plug-in and look for its dependencies. Each dependency will lead you to another plugin.xml file that will have its own dependencies. This chain of dependencies can quickly run into a large number of plugin.xml files to be parsed starting from the user-selected plug-in. Walk through these dependencies by writing a recursive function that can find the latest version of a plug-in (in case duplicate plug-ins are in the same system) and all its dependencies.
The steps required to write such a recursive function are listed below, and Listing 3 presents the source code of the function itself. Recursive functions can sometimes be very resource hungry and may not return results before a user loses patience. An alternative is to write a function that fetches only the immediate dependency list for a user-selected plug-in. See the loadImmediateDependencies() function in the sample code for this approach.
- Get the path location of the user-selected plug-in.
- Check whether plugin.xml or fragment.xml files exist at that location.
- Parse the plugin.xml or fragment.xml file to get a list of all plug-in IDs this plug-in requires.
- For each plug-in ID on this list, find the corresponding plug-in.
- If multiple plug-ins have the same ID, report it to the user only once and automatically decide to use the plug-in with the newest version. See Listing 4 on how to programmatically compare and find a newer-version plug-in.
- Add the plug-in (identified in Step 4 or 4a above) to a tree viewer and recursively call the same function to start over again from Step 1. Only this time, the user does not select the plug-in; rather, your code corresponding to Step 4 or 4a selects it.
Listing 3. The recursivePluginDependencyWalker() function
private Vector alreadyNotified = new Vector();
private boolean firstCall = true;
private TreeParent root = null;
private void recursivePluginDependencyWalker(PluginData pdObject,
TreeParent parentNode){
try {
String path = pdObject.getPluginLocation();
PluginParser pp = null;
File pluginDotXmlFile = new File(path + "/plugin.xml");
if(pluginDotXmlFile.exists()){
pp = new PluginParser(pluginDotXmlFile);
}else{
File fragmentDotXmlFile = new File(path +
"/fragment.xml");
if(fragmentDotXmlFile.exists()){
pp = new PluginParser(fragmentDotXmlFile);
}else{
return;//no plugin.xml or fragment.xml found
}
}
String displayName = pdObject.getDisplayName();
System.out.println("\nPlugin ["+ displayName + "]
requires" + "\n");
String requires[] = pp.getDependencyList();
if(0 != requires.length ){
for(int i=0; i<requires.length; i++){
System.out.println("\t" + requires[i] );
PluginData pd[] =
getPluginDataObjectsFromPluginID(requires[i]);
PluginData nextPlugin = null;
switch(pd.length){
case 0:
//great, we know there is
//something missing
nextPlugin = null;
break;
case 1:
//best case, everything will be smooth
nextPlugin = pd[0];
break;
default:
//worst case, there must be more
//than 1 plugin with the same id
//at different locations.
String msgLine1 =
"Plugin " + displayName +
" requires " +
requires[i] + "\n";
String msgLine2 =
"Duplicate plug-ins found for ID: \
" " + requires[i] +
"\"" +
"\n Continuing with higher version...
" ;
//it is bad to give repeated
//reminders,
//so remind only once per plugin id.
if(! alreadyNotified.contains(
new String(requires[i]))){
MessageDialog.openInformation(null,
"Dependency Walker",
msgLine1 +
msgLine2);
alreadyNotified.add(
new String(requires[i]));
}
//always take the better
//version anyway
nextPlugin =
getBetterVersionPlugin(pd);
break;
}//end of switch
if( null != nextPlugin ){
TreeParent nextinLine =
new TreeParent(
nextPlugin.getDisplayName(),
nextPlugin.isPlugin
LoadedInRegistry()
);
parentNode.addChild(nextinLine);
recursivePluginDependencyWalker(
nextPlugin,
nextinLine);
}else{
TreeParent nextinLine =
new TreeParent(
requires[i] +
" [This plug-in is missing]
",
false);
parentNode.addChild(nextinLine);
//obviously we can't recurse
//into a missing plugin...
}
}//end of for
}else{
System.out.println("\t NOTHING:
No further dependency \n" );
//no further dependency
}
} catch (Exception e) {
e.printStackTrace();
}
} |
At times, you will come across situations where a plug-in with the same ID is in two different locations. For example, a plug-in with the ID org.eclipse.xsd may be present in the <targetPlatform>\eclipse\plugins folder and in the <someLinkedPath>\eclipse\plugins folder.
In such cases, you must find out which plug-in should be considered out of the two or more copies available on the disk. Obviously, you will be interested in the latest plug-in, that is, the one with the newer version. You can find some existing functions to compare Eclipse plug-in versions, or you can write a simple function to compare plug-in versions based on the sample code in Listing 4.
Listing 4. Comparing plug-in versions
private PluginData getBetterVersionPlugin(PluginData pdo[]){
PluginData _pdObjs[] = pdo;
int len = pdo.length;
if(len==0)
return null;
Arrays.sort(_pdObjs,new Comparator() {
/**Compares its two arguments for order.
* Returns a negative integer, zero, or a positive integer
* as the first argument is less than, equal to, or greater than
* the second.
**/
public int compare(Object leftObj, Object riteObj) {
String leftPID = ((PluginData)leftObj).
getPluginVersion().replace('.', ':');
String ritePID = ((PluginData)riteObj).
getPluginVersion().replace('.', ':');
String leftID[] = leftPID.split(":");
String riteID[] = ritePID.split(":");
int maxlen = leftID.length > riteID.length ?
leftID.length : riteID.length;
for(int i=0; i<maxlen; i++){
int left = 0;
int rite = 0;
try {
left = new Integer(leftID[i]).intValue();
} catch (NullPointerException e) { left = 0; }
try {
rite = new Integer(riteID[i]).intValue();
} catch (NullPointerException e) { rite = 0; }
if(left==rite){
continue;
}else{
int bigger = left > rite ? left : rite;
if(bigger==left)
return 1;
if(bigger==rite)
return -1;
}
}
return 0;
}
public boolean equals(Object arg0) {
return false;
}
});
return _pdObjs[len-1];
}
|
After your code has walked through the complete chain of linked dependencies, you can represent it visually using a tree viewer. You should also visually indicate (see the red slashed circles in the following figure) the particular plug-in that caused a load failure.
The results of this search should look something like this:
Figure 2. Dependency Walker Tree View
If you want to locate some unresolved plug-in dependencies (missing plug-ins or plug-ins Eclipse did not load for some reason), first use the Eclipse PDE Plug-in Dependencies view to list your plug-in's dependencies. In case the Plug-in Dependencies view does not list your plug-in, you may want to use the ready-made tool in this article for a similar automated search covering all the linked plug-in folders. If you are interested in only specific plug-ins, you can also modify the source code to suit your requirements.
You can get the source code of this tool from the Download section below. To browse the source, unzip and open this plug-in as an Eclipse project. To use the tool, unzip and drop the plug-in in your \eclipse\plugins folder and do the following:
- In Eclipse, go to Window > Show View > Others > DependencyWalker Category and select the All Plugins in Target-Platform view.
- The view will display all the plug-ins physically present in the specified target platform. Select a plug-in and double-click it.
- The DependencyWalkerTreeView will list the dependencies of the plug-in you selected. Close this view every time you are done with it.
| Description | Name | Size | Download method |
|---|---|---|---|
| Unzip and open this plug-in as an Eclipse project | os-DependencyWalker.jar.zip | 54 KB | HTTP |
Information about download methods
Learn
-
The article "Getting started with the Eclipse Platform" (developerWorks, November 2002) provides a history and overview of Eclipse, including details on how to install Eclipse and plug-ins.
-
If you have trouble locating JAR files or get
NoClassDefFoundexceptions, take a look at JAR Class Finder, an Eclipse-based plug-in utility (alphaWorks, August 2003). -
Are you new to PDE? Perplexed by what a target platform is? Learn more by reading this introduction to PDE article.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
Get products and technologies
-
Innovate your next open source development project with
IBM trial software, available for download or on DVD.
Discuss
-
Get involved in the developerWorks community by participating in developerWorks blogs.

Indiver Dwivedi is a staff software engineer working in the Pune Lab for IBM India Software Labs. He joined IBM in 2000, and has worked on projects like Lotus SmartSuite and a data access tool for IBM Workplace. He has extensive programming experience in Ladder Logic, C, and C++. He has programmed logic controllers, and PC-based supervisory control and data acquisition (SCADA) software for industrial automation and control (IAC) systems. He has an interest in topics related to device communications and charting/plotting historical data stored by data acquisition systems under the IAC domain. He is currently working with a team in the IBM Pune Lab and contributing to the IBM Workplace Designer project.
Comments (Undergoing maintenance)





