Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 128262

Summary: Make public APIs for accessing PDE model
Product: [Eclipse Project] PDE Reporter: Julien Canches <julien.canches>
Component: UIAssignee: PDE-UI-Inbox <pde-ui-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: enhancement    
Priority: P3 CC: jerome.gout, mgoyal, paulslau, popescu
Version: 3.2   
Target Milestone: 3.3 M5   
Hardware: All   
OS: All   
Whiteboard:
Bug Depends on:    
Bug Blocks: 126575    
Attachments:
Description Flags
Resolution plan none

Description Julien Canches CLA 2006-02-16 12:34:39 EST
(I could not found a "core" component so I picked "Build" -- if I should have chosen "UI" please change appropriately)

The TPTP JUnit Plugin Test feature is currently relying on PDE internal APIs. TPTP is requesting an API way of performing the calls listed below.

1) PDE Model access:
- PDECore.getDefault().getModelManager().getWorkspaceModels()
- PDECore.getDefault().getModelManager().getExternalModels()
- PDECore.getDefault().getModelManager().findModel(IProject)
- PDECore.getDefault().getModelManager().getPlugins()

2) plugin.xml-based models saving
- ability to test whether a IPluginModelBase instance is a bundle-based or plugin-based plugin model (this is currently done by checking model instanceof BundlePluginModelBase or model instanceof WorkspacePluginModelBase)
- ability to save an a WorkspacePluginModelBase to a PrintWriter object

3) Target platform access:
ExternalModelManager.getEclipseHome()
TargetPlatform.getOS()
TargetPlatform.getOSArch()
TargetPlatform.getWS()
TargetPlatform.getNL()
TargetPlatform.getApplicationNames()
TargetPlatform.getDefaultProduct()

4) Runtime configuration directory setup:
TargetPlatform.createPlatformConfigurationArea(Map, File, String)
TargetPlatform.getConfigIniProperties(String)
Comment 1 Wassim Melhem CLA 2006-02-16 13:16:57 EST
past API freeze already
Comment 2 Julien Canches CLA 2006-09-12 10:32:11 EDT
Hi,

Are there any plans to provide public APIs that are equivalent to the internal methods listed above? TPTP is currently using these methods, we are trying to get rid of internal dependencies.
I'll be happy to discuss with a PDE member if you think that there is an alternate way to get the features provided by these methods, without requiring the PDE team to provide these APIs.

Regards,
Julien Canches -- TPTP Commiter
Comment 3 Paul Slauenwhite CLA 2006-10-25 12:34:47 EDT
Please increase the priority of this defect to P1 since it is required to resolve a blocking TPTP defect (https://bugs.eclipse.org/bugs/show_bug.cgi?id=126575).
Comment 4 Wassim Melhem CLA 2006-10-26 13:37:11 EDT
Hi Julien,

We need to better understand why the TPTP profiler needs access to all these PDE models to do its job.  I doubt that all this info is required by the profiler, and it is very possible that the problem lies elsewhere as was the case for bug 127197.  In that bug, the TPTP code was refactored in a way that got rid of its internal dependencies on PDE without making a single PDE model class API. 

To help us resolve this issue, the first step would be for you to go back to your code, examine where/why you are making references to these internal PDE classes, ensure it is done for a good reason and report back your findings.

At that point, we can advise if there are better alternatives or if there is something less drastic that can be done (e.g. make the PDE launchers less monolithic, etc.)

Paul, given our current knowledge/assessment of the situation, the current priority/severity of this bug report are appropriate.

Thanks.
Comment 5 Julien Canches CLA 2006-10-27 08:50:33 EDT
Hi Wassim,

I'm afraid there might be a confusion between the different TPTP projects. TPTP is made of four projects (Platform, Monitoring Tools, Testing Tools, Tracing and Profiling Tools). This request originates from the "Testing Tools" project, which aims at providing a generic testing framework.

In this testing framework, we provide five test implementations: JUnit, JUnit Plug-in, Manual, URL and Automated GUI Recording. When I first implemented JUnit Plug-in, I decided to use PDE internal APIs, because they perfectly matched my needs. I know this is wrong, but this was a long ago, and at that time I didn't see this as a big issue as it is today.

Basically, the JUnit Plug-in testing feature consists in:
(1) a synchronization mechanism between JUnit code and TPTP models (based on UML2.0 Testing Profile)
(2) a deployment model for specifying JUnit Plug-in test deployment (for details such as which host? which eclipse? which product/application? VM/program arguments? which plugins?)
(3) an editor for the deployment model
(4) a deployment mechanism that transfers the necessary bits to a remote host and creates an ad-hoc configuration area on the remote host
(5) a remote launcher that launches eclipse with the appropriate classpath / command line
(6) a remote agent (running as an eclipse plugin) that sends back test results to the local eclipse
The main difference with PDE JUnit plug-in tests is that TPTP supports deployment and execution of these tests to a remote host.
There is a general requirement to the user, that the remote eclipse instance must be identical to the target platform defined in PDE preferences (same plugins, same versions).

We currently rely on PDE for (2), (3) and (4), but this is for different reasons:

(2) We don't require the user to create a deployment model from scratch. We always provide him with a default deployment model, and this default is basically the target platform, as defined in PDE preferences. So we need the following information about the target platform:
- The target eclipse location
- The target details (OS, architecture, windowing system, locale)
- The default product and application
The first item is something that only PDE can provide us with. There may be alternatives for us to determine the remaining information, once we know the target platform's location.

(3) The editor enables the user to change the deployment details. The user can select an application or a product from a list, he can select which plugins must be active on the target platform. So we need the following information about the target platform:
- the list of available products
- the list of available applications
- the list of available plugins

(4) requires that we generate (a) a temporary MANIFEST.MF or plugin.xml file (b) a configuration area, and (c) a command line.
(a) Before deploying, we need to slightly modify the MANIFEST.MF or plugin.xml file of the project that contains the deployed JUnit test, to add the project's output directory to the plugin classpath. We use PDE to modify the plugin.xml's content. (We don't use PDE for modifying the MANIFEST.MF).
(b) The configuration area is first generated to a local temporary directory, and then transferred to the remote host. In the local phase, we use these pieces of information:
- The plugins available in the workspace
- If the user has picked the option "All plugins" in the editor (3), the plugins available on the target platform.
Once this information is collected, the configuration area (the "config" directory) must be generated. We call the following method to do that:
TargetPlatform.createPlatformConfigurationArea(pluginMap, area, brandingPlugin);
The output of this method is then slightly modified to translate paths of the local host to paths of the remote host.

I hope these details help you better understand why we are using these APIs. As a summary, here's the list of internal APIs we are using, annotated with the feature for which they are used. I've also added priorities (P1=we can't implement it ourselves, P2=there may be a work-around that involves code duplication, P3=there is a work-around with limited code duplication), but maybe you can provide us with guidance and we may lower the priority or remove the request.

1) PDE Model access:
- PDECore.getDefault().getModelManager().getWorkspaceModels() (4b) [P1]
Goal: get the list of plugins defined in the workspace by plugin projects.
- PDECore.getDefault().getModelManager().getExternalModels() (3)(4) [P1]
Goal: get the list of plugins available on the target platform.
- PDECore.getDefault().getModelManager().findModel(IProject) (4a) [P3]
Goal: retrieve the plugin model associated to a plugin project.
- PDECore.getDefault().getModelManager().getPlugins() (4b) [P3]
Goal: get a mixed list of workspace and external plugin models.

(In this list of APIs, there may be "conveniency" methods whose return value can be computed from the return value of a "core" method. The goal is to publish "core" methods only.)

2) plugin.xml-based models saving
- ability to test whether a IPluginModelBase instance is a bundle-based or
plugin-based plugin model (this is currently done by checking model instanceof
BundlePluginModelBase or model instanceof WorkspacePluginModelBase) (4a) [P2]
- ability to save a WorkspacePluginModelBase to a PrintWriter object (4a) [P2]
Goal: write to a temporary location a modified copy of an existing plugin model. The modification usually consists in adding the "bin/" folder to the plugin's classpath. The reason why we do this is that we deploy plugin projects to the remote host as is, but since we don't compile them into jars, their output directories must be added to the plugin classpath.

3) Target platform access:
ExternalModelManager.getEclipseHome() (2)(4) [P1]
Goal: get the location of the target platform.
TargetPlatform.getOS() (2) [P2]
Goal: get the OS attribute of the target platform.
TargetPlatform.getOSArch() (2) [P2]
Goal: get the arch attribute of the target platform.
TargetPlatform.getWS() (2) [P2]
Goal: get the ws attribute of the target platform.
TargetPlatform.getNL() (2) [P2]
Goal: get the nl attribute of the target platform.
TargetPlatform.getApplicationNames() (3) [P2]
Goal: present to the user the list of applications declared in the target platform so he can pick one.
TargetPlatform.getProductNames() (3) [P2]
Goal: present to the user the list of products declared in the target platform so he can pick one.
TargetPlatform.getDefaultProduct() (2) [P2]
Goal: get the default product that our default deployment will use (so the user does not have to edit the default generated deployment before launching).

4) Runtime configuration directory setup:
TargetPlatform.createPlatformConfigurationArea(Map, File, String) (4b) [P2]
Goal: create a "config" directory, for a given set of plugins, in the specified directory. This is necessary to launch eclipse on the remote host.
TargetPlatform.getConfigIniProperties(String) (4b) [P3]
Goal: read the target platform's config.ini file.

Thanks,
Julien
Comment 6 Wassim Melhem CLA 2006-10-30 01:43:32 EST
Hi Julien, thanks for the clarification.

This is indeed a very ambitious API request that puts us in an unpleasant situation. 

But we are where we are, so let's see what we can do here to help you out:

1) PDE Model Access
It will be very hard for you to get this info without PDE's help.  I am not sure what the APIs would look like here yet, but we will figure something out.

2) Saving models
This is non-negotiable NO.
We cannot open up these model classes as that will start a big chain reaction.

There are easy workarounds however:
If you want to test if a plug-in is a bundle or not, simply check if the project corresponding to the plug-in has a META-INF/MANIFEST.MF file or not.

If you want to modify the manifest.mf to add a bin/, you could easily use the jar.util.Manifest class to do this.
If you want to modify a plugin.xml, you can read it into a DOM and write it back out.


3) Target Platform access:

re: ExternalModelManager#getEclipseHome()
You don't need to directly call PDE code for this.  You can just get the value of the ECLIPSE_HOME Java variable (eg. JavaCore.getClasspathVariable(ECLIPSE_HOME)

As for the rest of the calls to Target Platform to query for os, ws, arch, ...
we could provide APIs for that.  These are non-controversial with 'String' return values.


4) Runtime Configuration directory setup
I suggest you copy these methods.  they are only a handful and very self-contained.
Comment 7 Julien Canches CLA 2006-10-31 05:19:11 EST
Created attachment 52975 [details]
Resolution plan
Comment 8 Julien Canches CLA 2006-10-31 05:21:40 EST
Comment on attachment 52975 [details]
Resolution plan

Please disregard this attachment, I added it to the wrong bugzilla. Sorry for the confusion.
Comment 9 Julien Canches CLA 2006-10-31 10:10:32 EST
Thanks Wassim,

It seems we have a fair solution to each of the requests I have made, either be it the intent of publishing an API, or a work-around.
I will now review all of my code to check if there are any issue, such as an additional dependency that would be introduced by copying bits of PDE code. I'll keep you informed.
Comment 10 Maneesh CLA 2006-11-14 11:24:28 EST
I am using PDE public api to save the Plugin Model as shown below, and it seems that the bundle manifest.mf is not supported. If PDE doesn't intend to support saving of models, why is the interface IEditable implemented by BundlePluginModel.

IPluginBase base = something;
if(base.getModel() instanceof IEditable) {
	StringWriter s = new StringWriter();
	PrintWriter myWriter = new PrintWriter(s);
	((IEditable) base.getModel()).save(myWriter);
	myWriter.flush();

	IResource resource = base.getModel().getUnderlyingResource();
	if (resource instanceof IFile) {
		IFile file = (IFile) resource;
		ByteArrayInputStream stream = null;
		try {
			stream = new ByteArrayInputStream(s.toString().getBytes("UTF8"));
			file.setContents(stream, true, true, new NullProgressMonitor());
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
}

Comment 11 Wassim Melhem CLA 2006-12-05 14:17:22 EST
re comment 10:

if you can find a way to write pde models by casting to IEditable, that is fine.  My point was that we do not plan on making the implementation of BundlePluginModel and friends public.

Note however that BundlePluginModel is a wrapper that represents two files, not just one: the manifest.mf and the plugin.xml.  It may not make sense for it to implement IEditable.  We need to change that if it does, since if you a pass a printwriter to the model, which of the two files is it supposed to be writing?   You need access to the individual files. 

In 3.3, we have implemented WorkspaceBundlePluginModelBase#save() to transparently write both manifest.mf and plugin.xml files.
Comment 12 Wassim Melhem CLA 2007-01-25 22:51:02 EST
Done.

re comment 0:
Request #1: There are static methods on org.eclipse.pde.core.plugin.PluginRegistry that will give you access to the models you need.

Request #2: you will do on your own, as agreed upon above.

Request #3: There is a new TargetPlatform class in an API pacakge now, which will give you access to all the methods you outline.  A couple of methods changed names, but the mapping from old to new should be obvious.

Request #4:  I decided to give you public access to TargetPlatform.createPlatformConfiguration(...) since copying it won't be trivial for you.  Note the slight change in the method name and the arguments it takes.

As for TargetPlatform.getConfigIniProperties(String), all we are doing here is reading a properties file.  There is nothing special here that requires API.

This officially concludes the TPTP API saga.
Comment 13 Paul Slauenwhite CLA 2007-01-26 07:59:59 EST
(In reply to comment #12)

Wassim, on behalf of TPTP and the Test Project, I want to thank you for you and your Team's efforts to resolve this defect.  Thanks!
Comment 14 Wassim Melhem CLA 2007-01-26 23:22:48 EST
you're welcome, Paul.  Glad to help.
Comment 15 Jerome Gout CLA 2007-01-30 04:30:13 EST
Hi Wassim,

I am terribly sorry but, it seems that Julien has forgotten to request an API for 

TargetPlatform.getBundleList()

which has not been exposed in the new PluginRegistry class.

I hope it would be possible to get this API in PluginRegistry ?

Thanks in advance.
Best regards,
Jerome (continuing the Julien's work)
Comment 16 Wassim Melhem CLA 2007-01-31 15:49:43 EST
Jerome,

The code in question can easily be copied into your code base without the need for API.  

However, it may get stale pretty quickly since this is one area of the runtime that keeps changing.

So to shield you from any future runtime changes that would break your launcher, I will provide API for that.