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. As of BASE 3.3, this extension point also support custom scripts and stylesheets. </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 Oracle.
Document the extension point! | |
---|---|
The |
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, etc. The action class may be as simple or complex as you like.
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 |
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.
ProxyActionFactory
:
This action factory can only be used if your action class is an interface
and all important methods starts with get
or is
.
The proxy action factory uses Java reflection to create a dynamic
proxy class in runtime. It will map all getX()
and isY()
methods to retreive the values from the corresponding parameter in the XML file.
For example, getIcon()
will retrieve the value
of the <icon>
tag and
isVisible()
from the <visible>
. The factory is smart enough to convert
the string to the correct return value for int, long,
float, double and boolean data types and
their corresponding object wrapper types, if this is needed.
BeanActionFactory
:
This action factory can be used if you have created a bean-like
class that implements the desired action class. The factory will
create an instance of the class specified by the
<beanClass>
parameter. The factory
will then use Java reflection to find set
method
for the other parameters. If there is a parameter <icon>
the factory first looks for a setIcon(String)
method. If it can't find that it will see if there is a getIcon()
method which has a return type, T. If so, a second attempt is made to find
a setIcon(T)
method. The factory is smart enough
to convert the string value from the XML file to the correct return value
for int, long, float,
double and boolean data types and their
corresponding object wrapper types, if this is needed.
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); } %>
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>