PluginExtensionPoints 

HOME INDEX SEARCH GO  

 <<O>>  Difference Topic PluginExtensionPoints (r1.4 - 10 Mar 2006 - DavidBeattie)
Changed:
<
<

package com.parasoft.test;
<nop>
>
>

package com.parasoft.test.impl;
<nop>
Changed:
<
<

  • If the value of the "beanClass" attribute in the extension point definition is not just an interface, but a fully instantiable class, then it is permissible to omit the "implementation" tag from the extension XML. The result is that the plugin framework will instantiate the class given in the "beanClass" attribute, for each extension that is defined on the extension point, with data initialized from the XML of the extension that is defined. This would be useful, for example, when all extensions should be instantiated the same, but with different property values set (read from the XML). It is also useful if the beanClass is set to "org.jdom.Element", if all you want in the extension mechanism is the ability to contribute arbitrary XML configuration data from multiple places to your extension point. The reverse, omitting the "beanClass" attribute, does not seem to be permissible (an exception would be thrown when the extension point is created by the plugin framework).
>
>

  • If the value of the "beanClass" attribute in the extension point definition is not just an interface, but a fully instantiable class, then it is permissible to omit the "implementation" tag from the extension XML. The result is that the plugin framework will instantiate the class given in the "beanClass" attribute, for each extension that is defined on the extension point, with data initialized from the XML of the extension that is defined. This would be useful, for example, when all extensions should be instantiated the same, but with different property values set (read from the XML). It is also useful if the beanClass is set to "org.jdom.Element", if all you want in the extension mechanism is the ability to contribute arbitrary XML configuration data from multiple places to your extension point. The reverse, omitting the "beanClass" attribute, does not seem to be permissible (an exception would be thrown when the extension point is created by the plugin framework).
  • The extension point attribute "beanClass" can be named "interface" instead (with the exact same contents--the name of a class or interface). This isn't officially documented, but in case the class being named is in fact intended to document an interface which will be implemented by each extension (the "normal case"), instead of a javabean to be instantiated and initialized with data (the case I documented immediately above), this naming makes more sense. If it were documented, using "interface" in the extension point with "implementation" in the extension, or as an alternative, simply "beanClass" in the extension point with no separate implementation class in the extension, just the field values to initialize in the bean instance, would make the most sense. (But since it's not documented, use at your own risk.)
  • Instead of using an "xmlns" attribute dot the XML element name as the name of the extension point to implement, we can use an attribute called "point" on the XML element. Like this:
    <extensions>
        <blah point="ParasoftJtest.testExtPoint" implementation="com.parasoft.test.impl.Extender"/>
    </extensions>
    
    And again "implementation" may be optional, and all of this is undocumented, so use at your own risk. (But it works in IDEA 5.0 and 5.1.)
Changed:
<
<

-- DavidBeattie - 08 Mar 2006

>
>

-- DavidBeattie - 09 Mar 2006


 <<O>>  Difference Topic PluginExtensionPoints (r1.3 - 09 Mar 2006 - DavidBeattie)
Added:
>
>

Alternate usage patterns

  • If the value of the "beanClass" attribute in the extension point definition is not just an interface, but a fully instantiable class, then it is permissible to omit the "implementation" tag from the extension XML. The result is that the plugin framework will instantiate the class given in the "beanClass" attribute, for each extension that is defined on the extension point, with data initialized from the XML of the extension that is defined. This would be useful, for example, when all extensions should be instantiated the same, but with different property values set (read from the XML). It is also useful if the beanClass is set to "org.jdom.Element", if all you want in the extension mechanism is the ability to contribute arbitrary XML configuration data from multiple places to your extension point. The reverse, omitting the "beanClass" attribute, does not seem to be permissible (an exception would be thrown when the extension point is created by the plugin framework).


 <<O>>  Difference Topic PluginExtensionPoints (r1.2 - 08 Mar 2006 - DavidBeattie)
Changed:
<
<

This information is currently based on IntelliJ IDEA 5.0. I haven't tried 5.1 or the 6.0 preview yet... hopefully the API doesn't change much, and at best, gets better documentation as the platform matures.

>
>

This information is currently based on IntelliJ IDEA 5.0. I haven't tried 5.1 or the 6.0 preview yet... hopefully the API doesn't change much, and at best, gets better documentation as the platform matures. But, some of what I am documenting below may change, since it is undocumented in the official IntelliJ Plugin SDK and was only learned by reading the source code provided with the Plugin SDK.

Changed:
<
<

See http://www.jetbrains.com/idea/openapi/5.0/com/intellij/ExtensionPoints.html

>
>

See http://www.jetbrains.com/idea/openapi/5.0/com/intellij/ExtensionPoints.html
and http://www.jetbrains.com/idea/openapi/5.1/com/intellij/ExtensionPoints.html

Changed:
<
<

Getting a list of extenders for an extension point.

>
>

Getting a list of extenders for an extension point

Changed:
<
<

Notice a few things which are not documented (or documented incorrectly) in the IntelliJ plugin docs, specifically, the string "name" of the extension point to pass to getExtensions() is a full name consisting of the concatenation of the Plugin id (not the plugin name as the documentation hints at, although if omitted, the id does default to the name), and the extension point name as defined in the XML, with a dot (".") in the middle. Secondly, I have no idea what the two-argument version of getExtensions() does, with an AreaInstance as the second argument, but it isn't necessary. All plugin.xml files, and in fact all built-in IntelliJ extension points seem to register themselves with the "root area" (Extensions.getRootArea()), which is supplied by default with the one-argument getExtensions() call.

>
>

Notice a few things which are not documented (or documented incorrectly) in the IntelliJ plugin docs, specifically, the string "name" of the extension point to pass to getExtensions() is a full name consisting of the concatenation of the Plugin id (not the plugin name as the documentation hints at, although if omitted, the id does default to the name), and the extension point name as defined in the XML, with a dot (".") in the middle. Secondly, I have no idea what the two-argument version of getExtensions() does, with an AreaInstance as the second argument, but it isn't necessary. All plugin.xml files, and in fact all built-in IntelliJ extension points seem to register themselves with the "root area" (Extensions.getRootArea()), which is supplied by default with the one-argument getExtensions() call.

Changed:
<
<

Extension instantiation details.

>
>

Extension instantiation details

Changed:
<
<

To be continued... this part is going to be really interesting.

>
>

Continuing the above plugin.xml sample (this could be in a separate plugin in its own plugin.xml file, or inside the same plugin.xml file if a plugin wants to extend its own extension point):

Changed:
<
<

-- DavidBeattie - 07 Mar 2006

>
>

<idea-plugin version="2" url="http://www.parasoft.com/">
    <extensions xmlns="ParasoftJtest">    
        <testExtPoint implementation="com.parasoft.test.impl.Extender"/>
        <testExtPoint implementation="com.parasoft.test.impl.ExtenderBean"/>
            <param1>Parameter Value 1</param1>
            <param2>true</param2>
        </testExtPoint>
        <testExtPoint implementation="org.jdom.Element">
            <param1>Another Value</param1>
            <container1>
                 <child1>More XML</child1>
            </container1>
        </testExtPoint>
    </extensions>
</idea-plugin>

Notice again that the "xmlns" attribute of the "extensions" tag should match the id of the plugin which defines the extension point. The children of the "extensions" tag, then, will be XML tags with tag-names corresponding to the names of any extension points which are desired to be contributed to. (You can mix and match extension implementations within a single "extensions" tag, if you want.) XML namespace (corresponding to plugin id), plus ".", plus XML child tag name, again, makes up the full String name of the extension point being extended. IDEA will give you an error if an "extensions" tag contains a child tag which attempts to implement an extension point which can't be found. Now, here are the classes needed to support the above:

package com.parasoft.test;

class Extender implements IExtensionPoint {

}

class ExtenderBean implements IExtensionPoint {
    private String param1;
    private boolean param2;
    
    public String getParam1() {
        return param1;
    }

    public void setParam1(String param1) {
        this.param1 = param1;
    }

    public boolean getParam2() {
        return param2;
    }

    public void setParam2(boolean param2) {
        this.param2 = param2;
    }
}

Now, if we call A.getExtenders(), we receive a 3-element array consisting of an instance of Extender, an instance of ExtenderBean with the fields set according to the XML, and an instance of org.jdom.Element corresponding to the XML rooted at the 3rd "testExtPoint" element of XML in the above sample. As you can see from the example, if you want XML automatically copied into fields of a class instance, IDEA will do that for you, but you must supply getters and setters in the style of the JavaBeans specification, because internally inside the extension API, java.beans.Introspector is used for the reflection to find the fields. In fact, if you don't have a getter and a setter (or a BeanInfo class defining the property and providing its getter and setter) for a field name corresponding to something in the XML, the API will generate an exception, rather than returning an array of objects. As an alternative, the org.jdom.Element instance may be useful since it would give a raw view to the XML of the extension, rather than instantiating any classes. This is completely undocumented though.

I don't know if it is necessary to have the extending classes implement or extend the interface class (like I demonstrated above), however, it seems to be good style to do so. IDEA may not check this as a constraint though, so it is up to user code to verify that the Objects which are returned are in fact instances of the interface they are supposed to implement (or an instance of org.jdom.Element if that feature is used).

-- DavidBeattie - 08 Mar 2006


 <<O>>  Difference Topic PluginExtensionPoints (r1.1 - 07 Mar 2006 - DavidBeattie)
Added:
>
>

%META:TOPICINFO{author="DavidBeattie" date="1141758600" format="1.0" version="1.1"}%

Plugin Extension Points

Overview

IntelliJ IDEA supports "extension points" inside a plugin.xml file. It supports both defining a new extension point, and extending an already-defined one. Eclipse plugin developers will recognize this idea immediately, and it may be useful to other developers as well.

Disclaimer

This information is currently based on IntelliJ IDEA 5.0. I haven't tried 5.1 or the 6.0 preview yet... hopefully the API doesn't change much, and at best, gets better documentation as the platform matures.

Built-in Extension points

See http://www.jetbrains.com/idea/openapi/5.0/com/intellij/ExtensionPoints.html

Custom extension points

Unfortunately, there is no documentation in the Javadoc for the IntelliJ API on how to use extension points yourself, aside from an example of how to define one in the plugin.xml file. Nor are there any examples anywhere. Fortunately, there is source code for openapi, distributed with the Plugin SDK. The following information was learned by reading the source code.

Architecture

Extension points and extensions form a one-to-many relationship. For any extension point defined, there can be many implementors of that extension point, which are all called "extensions" to that extension point. Typically, the plugin which defines the extension point will want to get access to all the class instances which extend the extension point, and do something with them, without knowledge of who those extenders are, except that they may implement a certain interface. This is why extension points are powerful... they provide a hook through which functionality can be added. At the plugin level, they mirror the interface / class instance model of Java, with an automatic class factory.

Getting a list of extenders for an extension point.

Given the following plugin.xml code:

<idea-plugin version="2" url="http://www.parasoft.com/">
    <name>Parasoft Jtest 7.5</name>
    <id>ParasoftJtest</id>
    <extensionPoints>
        <extensionPoint name="testExtPoint" beanClass="com.parasoft.test.IExtensionPoint"/>
    </extensionPoints>
</idea-plugin>

To retrieve the implementers of that extension point, use code like the following:

import com.intellij.openapi.extensions.Extensions;

class A {
    Object[] getExtenders() {
       Object[] extensions = Extensions.getExtensions("ParasoftJtest.testExtPoint");
       return extensions;
    }
}

Notice a few things which are not documented (or documented incorrectly) in the IntelliJ plugin docs, specifically, the string "name" of the extension point to pass to getExtensions() is a full name consisting of the concatenation of the Plugin id (not the plugin name as the documentation hints at, although if omitted, the id does default to the name), and the extension point name as defined in the XML, with a dot (".") in the middle. Secondly, I have no idea what the two-argument version of getExtensions() does, with an AreaInstance as the second argument, but it isn't necessary. All plugin.xml files, and in fact all built-in IntelliJ extension points seem to register themselves with the "root area" (Extensions.getRootArea()), which is supplied by default with the one-argument getExtensions() call.

Extension instantiation details.

To be continued... this part is going to be really interesting.

-- DavidBeattie - 07 Mar 2006


View | Diffs | r1.4 | > | r1.3 | > | r1.2 | More

e d i t a t t a c h r e f - b y d i f f s
Ideas,requests,problems regarding this site? Send feedback.
Copyright @ 2000-2003 by the contribution authors. All material on this collaboration tool is the property of the contributing authors.

Revision r1.1 - 07 Mar 2006 - 19:10 GMT - DavidBeattie
Revision r1.4 - 10 Mar 2006 - 01:44 GMT - DavidBeattie
Copyright © 2001 by the contributing authors. All material on this collaboration tool is the property of the contributing authors.
Ideas, requests, problems regarding this site? Send feedback.