27.6. Extension points

27.6.1. Error handlers

The BASE web client ships with a number of predefined extension points. Adding more extension points to the existing web client requires some minor modifications to the regular JSP files. But this is not what this chapter is about. This chapter is about defining new extension points as part of an extension. It is nothing magical about this and the process is the same as for the regular extension points in the web client.

The first thing you need to do is to start writing the XML definition of the extension point. Here is an example from the web client:

		

<extensions
   xmlns="http://base.thep.lu.se/extensions.xsd"
   >
   <extension-point
      id="net.sf.basedb.clients.web.menu.extensions"
      >
      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
      <name>Menu: extensions</name>
      <description>
         Extension point for adding extensions to the 'Extensions' menu.
         Extensions should provide MenuItemAction instances. The rendering
         is internal and extensions can't use their own rendering factories.
         The context will only include information about the currently logged
         in user, not information about the current page that is displayed.
         The reason for this is that the rendered menu is cached as a string
         in the user session. The menu is not updated on every page request.
         This extension point doesn't support custom stylesheets or javascripts.
      </description>
   </extension-point>
</extensions>

The <extensions> tag is the root tag and is needed to set up the namespace and schema validation.

The <extension-point> defines a new extension point. It must have an id attribute that is unique among all installed extension points. We recommend using the same naming conventions as for java packages. See Java naming conventions from Sun.

[Note] Document the extension point!

The <name> and <description> tags are optional, but we strongly recommend that values are provided. The description tag should be used to document the extension point. Pay special attention to the support (or lack of support) for custom scripts, stylesheets and renderers.

The <action-class> defines the interface or class that extensions must provide to the extension point. This must be a class or interface that is a subclass of the Action interface. We generally recommend that interfaces are used since this gives more implementation flexibility for action factories, but a regular class may work just as well.

The action class is used to carry information about the action, such as a title, which icon to use, a tooltip text, a javascript snippet that is invoked on click events, etc. The action class may be as simple or complex as you like.

[Note] Web client extension points

This is a note for the core developers. Extension points that are part of the web client should always define the action as an interface. We recommend that getId(), getClazz() and getStyle() attributes are always included if this makes sense. It is usually also a good idea to include isVisible() and isEnabled() attributes.

Now, if you are a good citizen you should also provide at least one implementation of an action factory that can create the objects of the desired type of action. The factory should of course be configurable from the XML file.

If you are lazy or if you want to immediately start testing the JSP code for the extension point, it may be possible to use one of the debugger action factories in the net.sf.basedb.util.extensions.debug pacakge.

It is finally time to write the JSP code that actually uses the extension point. It is usually not very complicated. Here is an exemple which lists snippets from a JSP file:


// 1. We recommend using the extensions taglib (and the BASE core taglib)
<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %>
<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>

// 2. Prepare the extension point
SessionControl sc = Base.getExistingSessionControl(pageContext, true);
JspContext jspContext = ExtensionsControl.createContext(sc, pageContext);
ExtensionsInvoker invoker = ExtensionsControl.useExtensions(jspContext, 
   "my.domain.name.extensionspoint");

// 3. Output scripts and stylesheets
<base:page title="My new extension point">
   <base:head>
      <ext:scripts context="<%=jspContext%>" />
      <ext:stylesheets context="<%=jspContext%>" />
   </base:head>
   <base:body>
   ....

// 4a. Using a taglib for rendering with the default renderer
<ext:render extensions="<%=invoker%>" context="<%=jspContext%>" />

// 4b. Or, use the iterator and a more hard-coded approach
<%
Iterator it = invoker.iterate();
while (it.hasNext())
{
   MyAction action = (MyAction)it.next();
   String html = action.getTitle() +
    ....
   out.write(html);
}
%>

27.6.1. Error handlers

An extension points may define a custom error handler. If not, the default error handler is used which simply writes a message to the log file. If you want to use a different error handler, create a <error-handler-factory> tag inside the extension point definition. The <factory-class> is a required subtag and must specify a class with a public no-argument constructor that implements the ErrorHandlerFactory interface. The <parameters> subtag is optional and can be used to specify initialization parameters for the factory just as for action and renderer factories.

		

<extensions
   xmlns="http://base.thep.lu.se/extensions.xsd"
   >
   <extension-point
      id="net.sf.basedb.clients.web.menu.extensions"
      >
      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
      <name>Menu: extensions</name>
      <error-handler-factory>
         <factory-class>
            ... some factory class ...
         </factory-class>
         <parameters>
            ... initialization parameters ...
         </parameters>
      </error-handler-factory>
   </extension-point>
</extensions>