Changeset 4206


Ignore:
Timestamp:
Apr 4, 2008, 8:42:33 AM (15 years ago)
Author:
Nicklas Nordborg
Message:

References #436: Create extension system for the web application

Updated documentation for the extension system.

Location:
trunk
Files:
7 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/build.xml

    r4205 r4206  
    13891389    <mkdir dir="${docbook.html.out}/admindoc/installation_upgrade"/>
    13901390    <mkdir dir="${docbook.html.out}/admindoc/plugin_installation"/>
     1391    <mkdir dir="${docbook.html.out}/admindoc/extensions"/>
    13911392    <mkdir dir="${docbook.html.out}/admindoc/coreplugin_configuration"/>
    13921393    <mkdir dir="${docbook.html.out}/developerdoc"/>
  • trunk/doc/src/docbook/admindoc/index.xml

    r3679 r4206  
    3131  <include file="installation_upgrade.xml"/>
    3232  <include file="plugin_installation.xml"/>
     33  <include file="extensions.xml" />
    3334  <include file="user_administration.xml"/>
    3435</part>
  • trunk/doc/src/docbook/developerdoc/api_overview.xml

    r4093 r4206  
    29822982  </sect1>
    29832983
     2984  <sect1 id="api_overview.extensions">
     2985    <title>Extensions API</title>
     2986   
     2987    <sect2 id="api_overview.extensions.core">
     2988      <title>The core part</title>
     2989   
     2990      <para>
     2991        The <emphasis>Extensions API</emphasis> is divided into two parts. A core
     2992        part and a web client specific part. The core part can be found in the
     2993        <package>net.sf.basedb.util.extensions</package> package and it's sub-packages.
     2994        The core part consists of three sub-parts:
     2995      </para>
     2996     
     2997      <itemizedlist>
     2998      <listitem>
     2999        <para>
     3000        A set of interface definitions which forms the core of the Extensions API.
     3001        The interfaces defines, for example, what an <interfacename
     3002        docapi="net.sf.basedb.util.extensions">Extension</interfacename> is and
     3003        what an <interfacename
     3004        docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename> should do.
     3005        </para>
     3006      </listitem>
     3007     
     3008      <listitem>
     3009        <para>
     3010        A <classname docapi="net.sf.basedb.util.extensions">Registry</classname> that is
     3011        used to keep track of installed extensions. The registry also provides
     3012        functionality for invoking and using the extensions.
     3013        </para>
     3014      </listitem>
     3015     
     3016      <listitem>
     3017        <para>
     3018        Utility classes that are useful when implementation a client application
     3019        that can be extendable. The most useful example is the <classname
     3020        docapi="net.sf.basedb.util.extensions.xml">XmlLoader</classname> which can
     3021        read extension definitions from XML files and create the proper factories,
     3022        etc.
     3023        </para>
     3024      </listitem>
     3025      </itemizedlist>
     3026     
     3027      <figure id="core_api.figures.extensions_core">
     3028        <title>The core part of the Extensions API</title>
     3029        <screenshot>
     3030          <mediaobject>
     3031            <imageobject>
     3032              <imagedata
     3033                align="center"
     3034                fileref="figures/uml/corelayer.extensions_core.png" format="PNG" />
     3035            </imageobject>
     3036          </mediaobject>
     3037        </screenshot>
     3038      </figure>
     3039     
     3040      <para>
     3041        The <classname docapi="net.sf.basedb.util.extensions">Registry</classname>
     3042        is one of the main classes in the extension system. All extension points and
     3043        extensions must be registered before they can be used. Typically, you will
     3044        first register extension points and then extensions, beacuse an extension
     3045        can't be registered until the extension point it is extending has been
     3046        registered.
     3047      </para>
     3048     
     3049      <para>
     3050        An <interfacename docapi="net.sf.basedb.util.extensions">ExtensionPoint</interfacename>
     3051        is an ID and a definition of an <interfacename docapi="net.sf.basedb.util.extensions">Action</interfacename>
     3052        class. The other options (name, description, renderer factory, etc.) are optional.
     3053        An <interfacename docapi="net.sf.basedb.util.extensions">Extension</interfacename>
     3054        that extends a specific extension point must provide an
     3055        <interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename>
     3056        instance that can create actions of the type the extension point requires.
     3057      </para>
     3058     
     3059      <example>
     3060        <title>The menu extensions point</title>
     3061        <para>
     3062        The <code>net.sf.basedb.clients.web.menu.extensions</code> extension point
     3063        requires <interfacename
     3064        docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemAction</interfacename>
     3065        objects. An extension for this extension point must provide a factory that
     3066        can create <classname>MenuItemAction</classname>:s. BASE ships with default
     3067        factory implementations, for example the <classname
     3068        docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname>
     3069        class, but an extension may provide it's own factory implementation if it wants to.
     3070        </para>
     3071      </example>
     3072     
     3073      <para>
     3074        Call the <methodname>Registry.useExtensions()</methodname> method
     3075        to use extensions from one or several extension points. This method will
     3076        find all extensions for the given extension points. If a filter is given,
     3077        it checks if any of the extensions or extension points has been disabled.
     3078        It will then call <methodname>ActionFactory.prepareContext()</methodname>
     3079        for all remaining extensions. This gives the action factory a chance to
     3080        also disable the extension, for example, if the logged in user doesn't
     3081        have the required permissions. The action factory may also set attributes
     3082        on the context. The attributes can be anything that the extension point
     3083        may make use of. Check the documentation for the specific extension point
     3084        for information about which attributes it supports. If there are
     3085        any renderer factories, their <methodname>RendererFactory.prepareContext()</methodname>
     3086        is also called. They have the same possibility of setting attributes
     3087        on the context, but can't disable an extension.
     3088      </para>
     3089     
     3090      <para>
     3091        After this, an <classname
     3092        docapi="net.sf.basedb.util.extensions">ExtensionsInvoker</classname>
     3093        object is created and returned to the extension point. Note that
     3094        the <methodname>ActionFactory.getActions()</methodname> has not been
     3095        called yet, so we don't know if the extensions are actually
     3096        going to generate any actions. The <methodname>ActionFactory.getActions()</methodname>
     3097        is not called until we have got ourselves an
     3098        <classname docapi="net.sf.basedb.util.extensions">ActionIterator</classname>
     3099        from the <methodname>ExtensionsInvoker.iterate()</methodname> method and
     3100        starts to iterate. The call to <methodname>ActionIterator.hasNext()</methodname>
     3101        will propagate down to <methodname>ActionFactory.getActions()</methodname>
     3102        and the generated actions are then available with the
     3103        <methodname>ActionIterator.next()</methodname> method.
     3104      </para>
     3105     
     3106      <para>
     3107        The <methodname>ExtensionsInvoker.renderDefault()</methodname>
     3108        and <methodname>ExtensionsInvoker.render()</methodname> are
     3109        just convenience methods that will make it easer to render
     3110        the actions. The first method will of course only work if the
     3111        extension point is providing a renderer factory, that can
     3112        create the default renderer.
     3113      </para>
     3114     
     3115      <note>
     3116        <title>Be aware of multi-threading issues</title>
     3117        <para>
     3118          When you are creating extensions you must be aware that
     3119          multiple threads may access the same objects at the same time.
     3120          In particular, any action factory or renderer factory has to be
     3121          thread-safe, since only one exists for each extension.
     3122          Action and renderer objects should be thread-safe if the
     3123          factories re-use the same objects.
     3124        </para>
     3125      </note>
     3126   
     3127    </sect2>
     3128   
     3129    <sect2 id="api_overview.extensions.web">
     3130      <title>The web client part</title>
     3131   
     3132      <para>
     3133        The web client specific parts of the Extensions API can be found
     3134        in the <package>net.sf.basedb.client.web.extensions</package> package
     3135        and it's subpackages. The top-level package contains classes used to
     3136        administrate the extension system. Here is for example the
     3137        <classname docapi="net.sf.basedb.client.web.extensions">ExtensionsControl</classname>
     3138        class which is the master controller for the web client extensions. It:
     3139      </para>
     3140     
     3141      <itemizedlist>
     3142      <listitem>
     3143        <para>
     3144        Keeps track of installed extensions and which JAR or XML file they are
     3145        installed from.
     3146        </para>
     3147      </listitem>
     3148     
     3149      <listitem>
     3150        <para>
     3151        Can, manually, or automatically, find and install new or
     3152        updated extensions and uninstall deleted extensions.
     3153        </para>
     3154      </listitem>
     3155     
     3156      <listitem>
     3157        <para>
     3158        Adds permission control to the extension system, so that only an
     3159        administrator is allowed to change settings, enable/disable extensions,
     3160        etc.
     3161        </para>
     3162      </listitem>
     3163      </itemizedlist>
     3164     
     3165      <para>
     3166        In the top-level package there are also some abstract classes that may
     3167        be useful to extend for developers creating their own extensions.
     3168        For example, we recommend that all action factories extend the <classname
     3169        docapi="net.sf.basedb.client.web.extensions">AbstractJspActionFactory</classname>
     3170        class.
     3171      </para>
     3172     
     3173      <para>
     3174        The sub-packages to <package>net.sf.basedb.client.web.extensions</package>
     3175        are mostly specific to a single extension point or to a specific type of
     3176        extension point. The <package>net.sf.basedb.client.web.extensions.menu</package>
     3177        package, for example, contains classes that are/can be used for extensions
     3178        adding menu items to the <menuchoice><guimenu>Extensions</guimenu></menuchoice>
     3179        menu.
     3180      </para>
     3181     
     3182      <figure id="core_api.figures.extensions_web">
     3183        <title>The web client part of the Extensions API</title>
     3184        <screenshot>
     3185          <mediaobject>
     3186            <imageobject>
     3187              <imagedata
     3188                align="center"
     3189                fileref="figures/uml/corelayer.extensions_web.png" format="PNG" />
     3190            </imageobject>
     3191          </mediaobject>
     3192        </screenshot>
     3193      </figure>
     3194   
     3195      <para>
     3196        When the web server is staring up, the <classname>ExtensionsServlet</classname>
     3197        is automatically loaded by Tomcat. This servlet has as it's only
     3198        task to initialise the extensions system by calling
     3199        <methodname>ExtensionsControl.init()</methodname>. This will result in
     3200        an initial scan for installed extensions, which is equivalent to doing
     3201        a manual scan with the force update setting to false. This means that
     3202        the extension system is up an running as soon as the first user log's
     3203        in to BASE.
     3204      </para>
     3205     
     3206      <para>
     3207        Using extensions only involves calling the
     3208        <methodname>ExtensionsControl.createContext()</methodname> and
     3209        <methodname>ExtensionsControl.useExtensions()</methodname> methods. This
     3210        returns an <classname docapi="net.sf.basedb.util.extensions">ExtensionsInvoker</classname>
     3211        object as described in the previous section.
     3212      </para>
     3213     
     3214      <para>
     3215        To render the actions it is possible to either use the
     3216        <methodname>ExtensionsInvoker.iterate()</methodname> method
     3217        and generate HTML from the information in each action. Or
     3218        (the better way) is to use a renderer together with
     3219        <classname docapi="net.sf.basedb.clients.web.taglib.extensions">Render</classname>
     3220        taglib.
     3221      </para>
     3222     
     3223      <para>
     3224        To get information about the installed extensions, 
     3225        change settings, enabled/disable extensions, performing a manual
     3226        scan, etc. use the <methodname>ExtensionsControl.get()</methodname>
     3227        method. This will create a permission-controlled object. All
     3228        users has read permission, administrators has write permission.
     3229      </para>
     3230     
     3231      <note>
     3232        <para>
     3233          The permission we check for is WRITE permission on the
     3234          web client item. This means it is possible to give a user
     3235          permissions to manage the extension system by assigning
     3236          WRITE permission to the web client entry in the database.
     3237          Do this from <menuchoice>
     3238            <guimenu>Administrate</guimenu>
     3239            <guimenuitem>Clients</guimenuitem>
     3240          </menuchoice>.
     3241        </para>
     3242      </note>
     3243   
     3244    </sect2>
     3245   
     3246  </sect1>
     3247
    29843248  <sect1 id="api_overview.other_api">
    29853249    <title>Other useful classes and methods</title>
  • trunk/doc/src/docbook/developerdoc/extensions.xml

    r4187 r4206  
    2727-->
    2828
    29 <chapter id="extensions">
     29<chapter id="extensions_developer">
    3030  <?dbhtml dir="extensions"?>
    31   <title>Extensions</title>
    32 
    33   <sect1 id="extensions.overview">
     31  <title>Extensions developer</title>
     32
     33  <sect1 id="extensions_developer.overview">
    3434    <title>Overview</title>
    3535    <para>
     
    4949      extensions. From this page, if you are logged in with enough permissions,
    5050      it is also possible to configure the extensions system, enable/disable
    51       extensions, etc.
     51      extensions, etc. Read more about this in <xref linkend="admin.extensions" />.
    5252    </para>
    5353
     
    6060    </para>
    6161
    62     <sect2 id="extensions.examplecode">
     62    <sect2 id="extensions_developer.examplecode">
    6363      <title>Download code examples</title>
    6464
     
    7070    </sect2>
    7171
    72     <sect2 id="extensions.terminology">
     72    <sect2 id="extensions_developer.terminology">
    7373      <title>Terminology</title>
    7474     
     
    190190  </sect1>
    191191 
    192   <sect1 id="extensions.helloworld">
     192  <sect1 id="extensions_developer.helloworld">
    193193    <title>Hello world as an extension</title>
    194194   
     
    337337
    338338
    339   <sect1 id="extensions.factories">
     339  <sect1 id="extensions_developer.factories">
    340340    <title>Custom action factories</title>
    341341
     
    612612</programlisting>
    613613   
     614    <note>
     615      <title>Be aware of multi-threading issues</title>
     616      <para>
     617        When you are creating custom action and renderer factories be
     618        aware that multiple threads may use a single factory instance
     619        at the same time. Action and renderer objects only needs to
     620        be thread-safe if the factories re-use the same objects.
     621      </para>
     622    </note>
     623   
    614624  </sect1>
    615625
    616   <sect1 id="extensions.resources">
     626  <sect1 id="extensions_developer.resources">
    617627    <title>Custom images, JSP files, and other resources</title>
    618628
     
    694704    </para>
    695705   
    696     <sect2 id="extensions.resources.scripts">
     706    <sect2 id="extensions_developer.resources.scripts">
    697707      <title>Javascript and stylesheets</title>
    698708     
     
    760770  </sect1>
    761771 
    762   <sect1 id="extensions.renderer">
     772  <sect1 id="extensions_developer.renderer">
    763773    <title>Custom renderers and renderer factories</title>
    764774
    765775    <para>
    766       TODO
    767     </para>
    768 
     776      It is always the responsibility of the extension point to
     777      render an action. The need for custom renderers is typically
     778      very small, at least if you want your extensions to blend into
     779      the look and feel of the BASE web client. Most customizations can
     780      be probably be handled by stylesheets and images. That said,
     781      you may still have a reason for using a custom renderer.
     782    </para>
     783   
     784    <para>
     785      Renderer factories are not very different from action factories.
     786      They are specified in the same way in the XML file and uses the
     787      same method for initialisation, including support for path
     788      conversion, etc. The difference is that you use a
     789      <sgmltag class="starttag">renderer-factory</sgmltag> tag
     790      instead of an <sgmltag class="starttag">action-factory</sgmltag>
     791      tag.
     792    </para>
     793
     794    <programlisting language="xml">
     795<![CDATA[
     796<renderer-factory>
     797   <factory-class>
     798      ... some factory class ...
     799   </factory-class>
     800   <parameters>
     801      ... some parameters ...
     802   </parameters>
     803</renderer-factory>
     804]]>
     805</programlisting>
     806
     807    <para>
     808      A <interfacename docapi="net.sf.basedb.util.extensions"
     809      >RendererFactory</interfacename> also has a <methodname>prepareContext()</methodname>
     810      method that can be used to tell the web client about any scripts or stylesheets
     811      the extension needs. If your renderer factory extends the <classname
     812        docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname>
     813      class you will not have to worry about this since you can configure
     814      scripts and stylesheets in the XML file.
     815    </para>
     816   
     817    <para>
     818      A render factory must also implement the <methodname>getRenderer()</methodname>
     819      which should return a <interfacename docapi="net.sf.basedb.util.extensions"
     820      >Renderer</interfacename> instance. The extension system will then call
     821      the <methodname>Renderer.render()</methodname> method to render an action.
     822      This method may be called multiple times if the extension created more than
     823      one action.
     824    </para>
     825   
     826    <para>
     827      The renderers responsibility is to generate the HTML
     828      that is going to be sent to the web client. To do this it needs
     829      access to the <classname
     830      docapi="net.sf.basedb.clients.web.extensions">JspContext</classname>
     831      object that was passed to the renderer factory. Here is a simple
     832      outline of both a renderer factory and renderer.
     833    </para>
     834   
     835    <programlisting language="java">
     836<![CDATA[
     837// File: MyRendererFactory.java
     838public class MyRendererFactory
     839   extends AbstractJspRendererFactory<MyAction>
     840{
     841
     842   public MyRendererFactory()
     843   {}
     844
     845   @Override
     846   public MyRenderer getRenderer(Context context, Extension extension)
     847   {
     848      return new MyRenderer((JspContext)context);
     849   }
     850}
     851
     852// File: MyRenderer.java
     853public class MyRenderer
     854   implements Renderer<MyAction>
     855{
     856
     857   private final JspContext context;
     858   public MyRenderer(JspContext context)
     859   {
     860      this.context = context;
     861   }
     862
     863   /**
     864      Generates HTML (unless invisible):
     865      <a class="[clazz]" style="[style]" onclick="[onClick]">[title]</a>
     866   */
     867   public void render(MyAction action)
     868   {
     869      if (!action.isVisible()) return;
     870      Writer out = context.getOut();
     871      try
     872      {
     873         out.write("<a");
     874         if (action.getClazz() != null)
     875         {
     876            out.write(" class=\"" + action.getClazz() + "\"");
     877         }
     878         if (action.getStyle() != null)
     879         {
     880            out.write(" style=\"" + action.getStyle() + "\"");
     881         }
     882         if (action.getOnClick() != null)
     883         {
     884            out.write(" href=\"" + action.getOnClick() + "\"");
     885         }
     886         out.write(">");
     887         out.write(HTML.encodeTags(action.getTitle()));
     888         out.write("</a>\n");
     889      }
     890      catch (IOException ex)
     891      {
     892         throw new RuntimeException(ex);
     893      }
     894   }
     895}
     896]]>
     897</programlisting>
    769898  </sect1>
     899 
     900  <sect1 id="extensions_developer.extension_points">
     901    <title>Extension points</title>
     902   
     903    <para>
     904      The BASE web client ships with a number of predefined extension
     905      points. Adding more extension points to the existing web client
     906      requires some minor modifications to the regular JSP pages. But this
     907      is not what this chapter is about. This chapter is about defining new
     908      extension points as part of an extension. It is nothing magical about
     909      this and the process is the same as for the regular extension points in
     910      the web client.
     911    </para>
     912   
     913    <para>
     914      The first thing you need to do is to start writing the
     915      XML definition of the extension point. Here is an example
     916      from the web client:
     917    </para>
     918   
     919    <programlisting language="xml">   
     920<![CDATA[
     921<extensions
     922   xmlns="http://base.thep.lu.se/extensions.xsd"
     923   >
     924   <extension-point
     925      id="net.sf.basedb.clients.web.menu.extensions"
     926      >
     927      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
     928      <name>Menu: extensions</name>
     929      <description>
     930         Extension point for adding extensions to the 'Extensions' menu.
     931         Extensions should provide MenuItemAction instances. The rendering
     932         is internal and extensions can't use their own rendering factories.
     933         The context will only include information about the currently logged
     934         in user, not information about the current page that is displayed.
     935         The reason for this is that the rendered menu is cached as a string
     936         in the user session. The menu is not updated on every page request.
     937         This extension point doesn't support custom stylesheets or javascripts.
     938      </description>
     939   </extension-point>
     940</extensions>
     941]]>
     942</programlisting>
     943   
     944    <para>
     945      The <sgmltag class="starttag">extensions</sgmltag> tag is the root tag and
     946      is needed to set up the namespace and schema validation.
     947    </para>
     948   
     949    <para>
     950      The <sgmltag class="starttag">extension-point</sgmltag> defines a new
     951      extension point. It must have an <sgmltag>id</sgmltag> attribute that
     952      is unique among all installed extension points. We recommend using
     953      the same naming conventions as for java packages. See <ulink
     954      url="http://java.sun.com/docs/codeconv/html/CodeConventions.doc8.html">Java naming
     955      conventions from Sun</ulink>.
     956    </para>
     957   
     958    <note>
     959      <title>Document the extension point!</title>
     960      <para>
     961        The <sgmltag class="starttag">name</sgmltag> and
     962        <sgmltag class="starttag">description</sgmltag> tags are optional.
     963        We recommend that the description tag is used to document the extension
     964        point. Pay special attention to the support (or lack of
     965        support) for custom scripts, stylesheets and renderers.
     966      </para>
     967    </note>
     968   
     969    <para>
     970      The <sgmltag class="starttag">action-class</sgmltag> defines the
     971      interface or class that extensions must provide to the extension
     972      point. This must be a class or interface that is a subclass
     973      of the <interfacename
     974      docapi="net.sf.basedb.util.extensions">Action</interfacename>
     975      interface. We generally recommend that interfaces are used since
     976      this gives more implementation flexibility for action factories, but
     977      a regular class may work just as well.
     978    </para>
     979     
     980    <para>
     981      The action class is used to carry information about the action,
     982      such as a title, which icon to use, a tooltip text, a javascript
     983      snippet that is invoked on click events, etc. The action class may
     984      be as simple or complex as you like.
     985    </para>
     986     
     987    <note>
     988      <title>Web client extension points</title>
     989      <para>
     990        This is a note for the core developers. Extension points that
     991        are part of the web client should always define the action as
     992        an interface. We recommend that <code>getId()</code>, <code>getClazz()</code>
     993        and <code>getStyle()</code> attributes are always included if this makes
     994        sense. It is usually also a good idea to include <code>isVisible()</code>
     995        and <code>isEnabled()</code> attributes.
     996      </para>
     997    </note>
     998     
     999    <para>
     1000      Now, if you are a good citizen you should also provide at least
     1001      one implementation of an action factory that can create the
     1002      objects of the desired type of action. The factory should
     1003      of course be configurable from the XML file.
     1004    </para>
     1005   
     1006    <para>
     1007      If you are lazy or if you want to immediately start testing the JSP code
     1008      for the extension point, it may be possible to use one of the debugger action
     1009      factories in the <package>net.sf.basedb.util.extensions.debug</package>
     1010      pacakge.
     1011    </para>
     1012   
     1013    <itemizedlist>
     1014    <listitem>
     1015      <para>
     1016      <classname
     1017      docapi="net.sf.basedb.util.extensions.debug">ProxyActionFactory</classname>:
     1018      This action factory can only be used if your action class is an interface
     1019      and all important methods starts with <code>get</code> or <code>is</code>.
     1020      The proxy action factory uses the Java reflection to create a dynamic
     1021      proxy class in runtime. It will map all <code>get</code> and <code>is</code>
     1022      methods to retreive the values from the corresponding parameter in the XML file.
     1023      For example, <methodname>getIcon()</methodname> will retrieve the value
     1024      of the <sgmltag class="starttag">icon</sgmltag> tag and
     1025      <methodname>isVisible()</methodname> from the <sgmltag
     1026      class="starttag">visible</sgmltag>. The factory is smart enough to convert
     1027      the string to the correct return value for <type>int</type>, <type>long</type>,
     1028      <type>float</type>, <type>double</type> and <type>boolean</type> data types and
     1029      their corresponding object types, if this is needed.
     1030      </para>
     1031    </listitem>
     1032   
     1033    <listitem>
     1034      <para>
     1035      <classname
     1036      docapi="net.sf.basedb.util.extensions.debug">BeanActionFactory</classname>:
     1037      This action factory can be used if you have created a bean-like
     1038      class that implements the desired action class. The factory will
     1039      create an instance of the class specified by the
     1040      <sgmltag class="starttag">beanClass</sgmltag> parameter. The factory
     1041      will then use Java reflection to find <code>set</code> method
     1042      for the other parameters. If there is a parameter <sgmltag class="starttag">icon</sgmltag>
     1043      the factory first looks for a <methodname>setIcon(String)</methodname>
     1044      method. If it can't find that it will see if there is a <methodname>getIcon()</methodname>
     1045      method which has a return type, T. If so, a second attempt is made to find
     1046      a <methodname>setIcon(T)</methodname> method. The factory is smart enough
     1047      to convert the string value from the XML file to the correct return value
     1048       for <type>int</type>, <type>long</type>, <type>float</type>,
     1049      <type>double</type> and <type>boolean</type> data types and their
     1050      corresponding object types, if this is needed.
     1051      </para>
     1052    </listitem>
     1053   
     1054    </itemizedlist>
     1055
     1056
     1057    <para>
     1058      It is finally time to write the JSP code that actually uses the
     1059      extension point. It is usually not very complicated. Here is
     1060      an exemple which lists snippets from a JSP page:
     1061    </para>
     1062
     1063    <programlisting>
     1064<![CDATA[
     1065// We recommend using the extensions taglib (and the BASE core taglib)
     1066<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %>
     1067<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
     1068
     1069// Prepare the extension point
     1070SessionControl sc = Base.getExistingSessionControl(pageContext, true);
     1071JspContext jspContext = ExtensionsControl.createContext(sc, pageContext);
     1072ExtensionsInvoker invoker = ExtensionsControl.useExtensions(jspContext,
     1073   "my.domain.name.extensionspoint");
     1074
     1075// Output scripts and stylesheets
     1076<base:page title="My new extension point">
     1077   <base:head>
     1078      <ext:scripts context="<%=jspContext%>" />
     1079      <ext:stylesheets context="<%=jspContext%>" />
     1080   </base:head>
     1081   <base:body>
     1082   ....
     1083
     1084// Using a taglib for rendering with the default renderer
     1085<ext:render extensions="<%=invoker%>" context="<%=jspContext%>" />
     1086
     1087// Using an iterator
     1088<%
     1089Iterator it = invoker.iterate();
     1090while (it.hasNext())
     1091{
     1092   MyAction action = (MyAction)it.next();
     1093   String html = action.getHtml();
     1094   out.write(html);
     1095}
     1096%>
     1097]]>
     1098</programlisting>
     1099
     1100  </sect1>
     1101 
    7701102</chapter>
Note: See TracChangeset for help on using the changeset viewer.