The Extensions API is divided into two parts. A core part and a web client specific part. The core part can be found in the net.sf.basedb.util.extensions package and it's sub-packages, and consists of three sub-parts:
Utility classes that are useful when implementation a client application
that can be extendable. The most useful example is the
XmlLoader which can
read extension definitions from XML files and create the proper factories,
is one of the main classes in the extension system. All extension points and
extensions must be registered before they can be used. Typically, you will
first register extension points and then extensions, beacuse an extension
can't be registered until the extension point it is extending has been
is an ID and a definition of an
class. The other options (name, description, renderer factory, etc.) are optional.
that extends a specific extension point must provide an
instance that can create actions of the type the extension point requires.
Example 29.1. The menu extensions point
net.sf.basedb.clients.web.menu.extensions extension point
objects. An extension for this extension point must provide a factory that
MenuItemAction:s. BASE ships with default
factory implementations, for example the
class, but an extension may provide it's own factory implementation if it wants to.
to use extensions from one or several extension points. This method will
find all extensions for the given extension points. If a filter is given,
it checks if any of the extensions or extension points has been disabled.
It will then call
for all remaining extensions. This gives the action factory a chance to
also disable the extension, for example, if the logged in user doesn't
have a required permission. The action factory may also set attributes
on the context. The attributes can be anything that the extension point
may make use of. Check the documentation for the specific extension point
for information about which attributes it supports. If there are
any renderer factories, their
is also called. They have the same possibility of setting attributes
on the context, but can't disable an extension.
After this, an
object is created and returned to the extension point. Note that
ActionFactory.getActions() has not been
called yet, so we don't know if the extensions are actually
going to generate any actions. The
is not called until we have got ourselves an
ExtensionsInvoker.iterate() method and
starts to iterate. The call to
will propagate down to
and the generated actions are then available with the
just convenience methods that will make it easer to render
the actions. The first method will of course only work if the
extension point is providing a renderer factory, that can
create the default renderer.
|Be aware of multi-threading issues|
When you are creating extensions you must be aware that multiple threads may access the same objects at the same time. In particular, any action factory or renderer factory has to be thread-safe, since only one exists for each extension. Action and renderer objects should be thread-safe if the factories re-use the same objects.
Any errors that happen during usage of an extension is handled by an
The core provides two implementations. We usually don't want the
errors to show up in the gui so the
is the default implementation that only writes to the log file. The
error handler can be used to re-throw exceptions which usually means that
they trickle up to the gui and are shown to the user. It is also
possible for an extension point to provide its own implementation of
The web client specific parts of the Extensions API can be found
in the net.sf.basedb.client.web.extensions package
and it's subpackages. The top-level package contains classes used to
administrate the extension system. Here is for example the
class which is the master controller for the web client extensions. It:
Keeps track of installed extensions and which JAR or XML file they are installed from.
Can, manually or automatically, find and install new or updated extensions and uninstall deleted extensions.
Adds permission control to the extension system, so that only an administrator is allowed to change settings, enable/disable extensions, etc.
In the top-level package there are also some abstract classes that may
be useful to extend for developers creating their own extensions.
For example, we recommend that all action factories extend the
The sub-packages to net.sf.basedb.client.web.extensions are mostly specific to a single extension point or to a specific type of extension point. The net.sf.basedb.client.web.extensions.menu package, for example, contains classes that are/can be used for extensions adding menu items to the menu.
Initialise the extensions system by calling
ExtensionsControl.init(). This will result in
an initial scan for installed extensions, which is equivalent to doing
a manual scan with the force update setting to false. This means that
the extension system is up an running as soon as the first user log's
in to BASE.
Act as a proxy for custom servlets defined by the extensions. URL:s
.servlet has been mapped to the
ExtensionsServlet. When a request is made it
will extract the name of the extension's JAR file from the
URL, get the corresponding
and then invoke the custom servlet. More information can be found in
Section 27.7, “Custom servlets”.
Using extensions only involves calling the
ExtensionsControl.useExtensions() methods. This
object as described in the previous section.
To render the actions it is possible to either use the
and generate HTML from the information in each action. Or
(the better way) is to use a renderer together with the
To get information about the installed extensions,
change settings, enabled/disable extensions, performing a manual
scan, etc. use the
method. This will create a permission-controlled object. All
users has read permission, administrators has write permission.
The permission we check for is WRITE permission on the web client item. This means it is possible to give a user permissions to manage the extension system by assigning WRITE permission to the web client entry in the database. Do this from→ .
is mapped to handle the compilation
which are regular JSP files with a different extension. This feature is
experimental and requires installing an extra JAR into Tomcat's lib
directory. See Section 23.2, “Installing the X-JSP compiler” for