Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[ve-dev] Classpath Container Contributions


The VE has several needs for contributions to configure dynamically what happens. Most of the contributions are based upon the classpath. If a certain "path" is in the project's classpath, then certain contributions need to be processed. Also, these contributions come from plugins that provide libraries to be used by the VE. For example, the ve.swt plugin provides the contributions for working with SWT. One of things it can contribute is the SWT jar itself.

There are many ways to get "paths" into the classpath, e.g. external jars, variables, or containers. In the past we supported variables. However variables are restrictive in that they are basically one path for the entire workspace and that is it. Containers are much more flexible, they allow different sets of paths to be contributed to each individual project.

My proposal is that contributions will be based upon containers only, and not variables (we never supported external jars for contributions). One question would be that should we continue to support variables. The predecessor from Websphere(TM) Application Developer didn't officially support the extensions we are talking about. They were there and disclosed to customers through articles, but it was made clear that the API's being used can and will change in the future. For one thing, all of the package names have changed from com.ibm... to org.eclipse....

Here is the list of contributions that we currently have based upon classpath:
  • Proxy configuration contributions (e.g. jars to go into classpath, dll's to go into java.library.path, arguments to send to the remote vm, other configuration changes, etc).
  • Beaninfo contributions (e.g. beaninfo jars and search paths, and override files)
  • VE contributions (e.g. palette categories)


To allow for simplicity we will have one combined extension point that should handle the majority of the cases. This can be seen later in the "Putting it all together" section below. For full flexibility there will be specific extention points for proxy, BeanInfo, and VE contributions. These are discussed below in their own sections.

Let's start with full flexibility. Proxy, Beaninfo, and VE will have individual container contribution extension points. However, to simplify code, when looking for the contribution for a particular container, these plugins will first check the standard java container (retrieved from JavaCore) for the given container path and see if it implements the particular contribution interface in question. If it does, it will go to the container and request the information. Then it will go through its own extension point looking for contributions for that container and have each one have a go at it.

By doing it this way, a developer can have one contribution, the java classpath container contribution, handle all of the contribution types. And there won't be a need to specify all three types of contributions separately. By also then going on to look through the rest of the contributions, it allows plugins to extend the contributions that were specified in a different plugin. For instance, this allows us to supply java JFC contributions, even though the JRE container was contributed by a base Eclipse plugin.

To simplify things even further for a developer, we will supply a class that implements all three contribution types plus the java classpath container that can then be customized through the plugin.xml. That way a simple contribution can be handled easily without having to write all of these contributors.


Proxy Contributions:

These configuration contributors only affect the configuration used to launch the remote vm. The remote vm is used for BeanInfo and for the VE java editor. They do not affect the build classpath. That can only be affected by the IClasspathContainer and the user. The build path cannot be extended in any other way.

Within org.eclipse.jem.proxy:

<extension-point id="contributor" name="Proxy Configuration Contributor"/>

And when used:

<extension point="org.eclipse.jem.proxy.contributor">
  <contributor id="container-id" class="configurationclass"/>
</extension>

Where for the container with "container-id" the configurationClass is instantiated and used as a contributor.
Where "configurationClass" implements the interface org.eclipse.jem.proxy.core.IConfigurationContributor.

So whenever a container entry is found in the classpath, that container entry is first used to find the JavaCore IClasspathContainer, and if it exists and it implements IConfigurationContributor, it will be used to contribute. Then the contributor extension point will be used to find any other registered contributors for that container.

We will supply a default abstract implementation of this contributor that developers may subclass. It will provide some convienent functions for working with the configuration.

This allows for complicated contributors (i.e. something beyond a jar to be added to classpath, we which we discuss next), either in one place through the IClasspathContainer, or through registered contributors. The registered contributors point would most likely be used if extending any existing classpath container from another plugin, such as what we do with java for the JFC.

The order of processing will be:
  1. IClasspathContainer (if it implements IConfigurationContributor) for the container path.
  2. In plugin order, (i.e. from the plugin with no dependencies to the leaves, such that no plugin will be processed before one of its required plugins), the plugin is the one where the extension is located. Contributor extension point entries for the container path in the plugin (there may be more than one, though it doesn't make sense, the order processed is undefined within a particular plugin)


BeanInfo Contributions:

These contributions are used to contribute a beaninfo jar(s) and override file(s) for a container path. (Note: We did support variables too, but we will not supporting them for BeanInfo extension point contributions).

Within org.eclipse.jem.beaninfo:

<extension-point id="contributor" name="BeanInfo Contributor"/>

And when used:

<extension point="org.eclipse.jem.beaninfo.contributor">
  <contributor id="container-id" class="contributorClass"/>
</extension>

Where for the container with "container-id" the contributorClass is instantiated and used as a contributor.
Where "contributorClass" implements the interface org.eclipse.jem.beaninfo.core.IBeanInfoContributor.

So whenever a container entry is found in the classpath, that container entry is first used to find the JavaCore IClasspathContainer, and if it exists and it implements IBeanInfoContributor, it will be used to contribute. Then the contributor extension point will be used to find any other registered contributors for that container.

This allows for complicated contributors (i.e. something beyond a beaninfo jar to be added to classpath or overrides, we which we discuss next), either in one place through the IClasspathContainer, or through registered contributors. The registered contributors point would most likely be used if extending any existing classpath container from another plugin, such as what we do with java for the JFC.

There will be one more simplified extension point for contributing just the beaninfo jar/searchpath/overrides. If there are no complications to the contribution, this will be a simpler way to do it.

Within org.eclipse.jem.beaninfo:

<extension-point id="registration" name="BeanInfo registrations"/>

And when used:

<extension point="org.eclipse.jem.beaninfo.registration">
  <container id="container-id">
    <beaninfo path="beaninfo-library-path">
      <searchpath package="java-package-to-search"/>
    </beaninfo>
    <override package="package-name" path="override-file-path"/>
  </container>
</extension>

There may be one or more <container> elements, and there may be zero or more <beaninfo> elements for a container, zero or more <searchpath> elements for a beaninfo element, and zero or more <override> elements for a container.

Where for the container with "container-id" the given beaninfo and overrides will be applied. The beaninfo-library-path will be a path to a jar in a plugin. If it is not absolute (i.e. doesn't start with a '/') then it will be assumed to be relative to the plugin that is defining the extension. Otherwise the first segment of the path will be the name of the plugin where the file will be found. The rest of the path will be relative to that plugin.  Note we will handle debug mode where if started from another Eclipse IDE we can automatically detect that the library is not found, using the debug proxy.jars file protocol, the build output folder is found instead. It must be in a plugin somewhere. Since this is for plugin contributions, it doesn't make sense to have a path to hard-coded directory like "c:/something". It couldn't be distributed properly in that case.

Note: The old format also had a kind="plugin" attribute on the beaninfo element, but the other kinds, like project or variable, really don't make sense for a plugin contribution, so we are simplifying it down to just kind="plugin" by default, and so not specify it.

Where "java-package-to-search" is the BeanInfo package containing BeanInfos for this jar. The package name will be added to the BeanInfo searchpath.

Where "package-name" is the package or package fragment (i.e. part of a package, such as org.eclipse is a package fragment of org.eclipse.ve) and the override file to use when that package fragment is found when the container is in the class path. "override-file-path" is the path to a directory containing *.override files. For instance, if the package fragment was "java.awt", then in directory pointed to would be files like "Container.override". If the fragment was not a leaf fragment (e.g. "java"), then under that directory would be more directories containing the rest of the package name. For example, there could be a directory "lang" with a file named "Object.override" in that directory.

The override file path, if not absolute (i.e. doesn't start with a "/") then it will be assumed to be relative to the plugin that is defining the extension. Otherwise the first segment of the path will be the name of the plugin where the directory will be bound. The rest of the path will be relative to that plugin. Since this is for plugin contributions, it doesn't make sense to have a path to hard-coded directory like "c:/something". It couldn't be distributed properly in that case.

Note: The old format used a URL instead here, but we always used "platform:/plugin/pluginname/..." anyway, so it makes sense to simplify it down to just be in a plugin.


The order of processing will be:
  1. IClasspathContainer (if it implements IBeanInfoContributor) for the container path.
  2. The following in plugin order, (i.e. from the plugin with no dependencies to the leaves, such that no plugin will be processed before one of its required plugins), the plugin is the one where the extension is located:
  3. Contributor extension point entries for the container path in the plugin (there may be more than one, though it doesn't make sense, the order processed is undefined within a particular plugin)
  4. Registration extension point entries for the container path in the plugin. (the order processed is undefined within a particular plugin).


VE (Java Editor) Contributions:

Currently the only VE (Java editor) specific contribution pertaining to container path is the palette categories to add to the palette. There will probably be more in the future.

Within org.eclipse.ve.java.core:

<extension-point id="contributor" name="VE Java Editor Contributor"/>

And when used:

<extension point="org.eclipse.ve.java.core.contributor">
  <contributor id="container-id" class="contributorClass"/>
</extension>

Where for the container with "container-id" the contributorClass is instantiated and used as a contributor.
Where "contributorClass" implements the interface org.eclipse.ve.java.core.IVEContributor.

So whenever a container entry is found in the classpath, that container entry is first used to find the JavaCore IClasspathContainer, and if it exists and it implements IVEContributor, it will be used to contribute. Then the contributor extension point will be used to find any other registered contributors for that container.

This will probably rarely used. Instead the next section, "Putting it all together" will be more applicable.

Putting it all together:

Now putting it all together for the simple case. This is the case where a plugin is contributing a container, a jar, a beaninfo jar, override files, and a palette cat. For this case, we will supply several prepackaged configurable classes to use in certain extension points to pull it all together.

The first class is  org.eclipse.ve.java.wizard.DefaultClasspathContainerWizardPage. This is used to have your container show up in the Add Library page. The current one changes the container over to be a variable, but we won't be doing that now. It will simply add a classpath entry to the specified container with no extended path info.

The next class is org.eclipse.ve.java.core.DefaultClasspathContainerInitializer. This is a default classpath container initializer. It will create a special default IClasspathContainer  (org.eclipse.ve.java.core.DefaultClasspathContainer) that also implements IConfigurationContributor from Proxy, the IBeanInfoContributor from BeanInfo, and the IVEContributor from VE. This classpath container will use a new extension point, discussed below, which glombs together most of the previous extension points into one registration.

The new registration that will be used be org.eclipse.ve.java.core.DefaultClasspathContainer will be:

Within org.eclipse.ve.java.core:

<extension-point id="registration" name="Standard registrations"/>

And when used:

<extension point="org.eclipse.ve.java.core.registration">
  <registration id="container-id"
      configurationContributor="configurationContributorClass"
      paletteCats="palette-xmi-file"
      paletteLoc="last">
    <library runtime="library-path" source="source-path" sourceroot="root-path">
    <beaninfo path="beaninfo-library-path">
      <searchpath package="java-package-to-search"/>
    </beaninfo>
    <override package="package-name" path="override-file-path"/>
  </registration>
</extension>


All of the elements/attributes are optional. If not found, the default will occur.

There can zero or more <library> elements. There can be zero or more <beaninfo> and <override> elements.

This is what happens with DefaultClasspathContainer in its IClasspathContainer role. It will find all of the <library> elements at the registration level and create classpath entries for each of them. The "library-path" and "source-path" must be relative to a plugin (just like discussed above, if no leading "/" then it is the plugin where the extension is declared).

This is what happens with DefaultClasspathContainer in its IConfigurationContributor role. It will instantiate the "configurationContributorClass" and pass on the configuration requests to it.

This is what happens with DefaultClasspathContainer in its IBeanInfoContributor role. It will find all of the <beaninfo> and <override> elements and add them appropriately.

This is what happens with DefaultClasspathContainer in its IVEContributor role. It will find the paletteCats attribute and add it at the position indicated by paletteloc. The only valid value for paletteLoc is "last". If not specified, the palette cats will be inserted at the beginning of the palette. The "palette-xmi-file" must be relative to the plugin defining the extension.

Note: The paletteCats used to be a URL, but it makes more sense that is relative to the plugin instead.

So it all will look like this:

<extension point="org.eclipse.jdt.ui.classpathContainerPage">
  <classpathContainerPage
    name="Examples"
    class="org.eclipse.ve.java.wizard.DefaultClasspathWizardPage"
    id="container-id">
  </classpathContainerPage>
</extension>

<extension point="org.eclipse.jdt.core.classpathContainerInitializer">
  <classpathContainerInitializer
    class="org.eclipse.ve.java.core.DefaultClasspathContainerInitializer"
    id="container-id">
  </classpathContainerInitializer>
</extension>

   <extension point="org.eclipse.ve.java.core.registration">
     <registration id="JAVA_EXAMPLE"
         configurationContributor="org.eclipse.ve.examples.java.JavaExampleContributor"
         palettecats="examplecats.xmi">
       <library
           runtime="vm/javaexamplebeans.jar"
           source="vm/javaexamplebeanssrc.zip"/>
       <additionalLibrary>
         <library>archiver.jar<library>
         <library>crimson.jar<library>
              </additionalLibrary>
       <beaninfo path="vm/javaexamplebeaninfo.jar">
         <searchpath package="org.eclipse.ve.examples.java.beaninfo"/>
       </beaninfo>
      <override
          package="org.eclipse.ve.examples.java.vm"
          path="overrides/org/eclipse/ve/examples/java/vm">
      </override>
     </registration>
   </extension>

Where "container-id" is the id of the container for this simple contribution (such as JRE_CONTAINER, though we couldn't use that because already used).

Note: In the current classpath wizard page we also pass in the variable id, but technically not necessary because we can get access to the "id" attribute from the classpathContainerPage element itself.

In summary:

By having these different extension points we can allow for simplicity for 90% of the cases, but allowing full flexibility if required by the full set of extension points.

Thanks,
Rich Kulp

Back to the top