James
Translated
Downloads
Current Documentation
Older Documentation
Project
Jakarta Information (web)
Related Projects (web)
|
Writing a Custom Matcher |
Implementing a custom matcher is generally a simple task, most of whose complexity
lies in coding the actual work to be done by the matcher. This is largely due to the
simplicity of the Matcher interface and the fact that a couple of abstract Matcher template
classes are provided in the Mailet package. These two classes, GenericMatcher and
GenericRecipientMatcher, greatly simplfy the task of Matcher authoring.
As discussed elsewhere in this manual, the Matcher interface does not simply match
or not match a particular message. Rather, it returns some subset of the original message
recipients as a result of the match(Mail) method. This leads to the two different abstract
Matcher implementations.
The first, GenericMatcher, is intended for matchers where recipient evaluation is not
necessary. Basically, you should subclass this implementation if your matcher is going to
return all or none of the recipients.
When subclassing this class, there are four methods that potentially need to be
overridden. These are getMatcherInfo(), init(), match(Mail), and destroy(). More on these
anon.
The second implementation, GenericRecipientMatcher, is intended for those matchers where
each recipient is evaluated individually. It is a subclass of GenericMatcher, and inherits
most of its behavior from that class. The only major difference is that subclasses are
expected to override matchRecipient(MailAddress) rather than match(Mail).
Configuration |
Matchers are passed a single String as part of their configuration. Interpretation of this
list is left entirely to the body of the Matcher. This String value is available in
the body of the Matcher through use of the getCondition() method of the
GenericMatcher class. This method returns the String value passed to the Matcher, and returns
null if no value is set. The method getCondition() is available inside the init(), destroy(), match(Mail),
and matchRecipient(MailAddress) methods.
|
Logging |
There is a simple logging mechanism provided by the Mailet API. It does not support
logging levels, so any log filtering will have to be implemented in the Matcher code.
Logging is done by calling one of the two logging methods on GenericMatcher/GenericRecipientMatcher - log(String)
or log(String,Throwable). Logging is available inside the init(), destroy(), match(Mail),
and matchRecipient(MailAddress) methods.
The value of getMatcherInfo() for the Matcher is prepended to the log entries for that
Matcher. So it may be desirable for you to override this method so you can distinguish Matcher
log entries by Matcher.
|
Initialization |
As part of the Matcher lifecycle, a Matcher is guaranteed to be initialized immediately after
being instantiated. This happens once and only once for each Matcher instance. The
Initialization phase is where configuration parsing and per-Matcher resource creation generally
take place. Depending on your Matcher, it may or may not be necessary to do any initialization
of the Matcher. Initialization logic is implemented by overriding the init() method of
GenericMatcher/GenericRecipientMatcher.
|
Matching |
It is the matching phase where the Matcher's work is done. The exact form of this phase largely
depends on which Matcher superclass is subclassed.
If GenericMatcher is being subclassed, it is the match(Mail) that is implemented. As described
above, this method returns a Collection of MailAddresses that is a subset of the original
recipients for the Mail object.
If it is a purely recipient-filtering Matcher, then the GenericRecipientMatcher should be
subclassed. In this case, developers must provide an implementation of the
matchRecipient(MailAddress) method. This method returns true if the recipient matches,
and false otherwise.
|
Destruction |
As part of the Matcher lifecycle, a Matcher is guaranteed to be destroyed when the container
cleans up the Matcher. This happens once and only once for each Matcher instance. The
Destruction phase is where per-Matcher resource release generally takes place. Depending
on your Matcher, it may or may not be necessary to do any destruction
of the Matcher. Destruction logic is implemented by overriding the destroy() method of
GenericMatcher/GenericRecipientMatcher.
|
|
Deploying a Custom Matcher |
Once a Matcher has been successfully implemented there are only a couple of
additional steps necessary to actually deploy the Matcher.
Adding Your Matcher to the Classpath |
The Matcher must be added to James' classpath so that the Matcher can be loaded by James. There
are two ways to add a custom Matcher to the classpath so that James will be able to load the
Matcher. These are:
1. Download the source distribution, add a jar file containing the custom files to the lib
directory of the unpacked source distribution, and build a new .sar file by following the
directions here. This new .sar file will now
include your custom classes.
or
2. Place a jar file containing the custom class files in the lib subdirectory of the James
installation. It will also be necessary to unpack the JavaMail and James jar files from
the provided .sar file and add them to this directory.
|
James Configuration |
Configuration of the processor chain is discussed
elsewhere in this documentation. The
details of configuring matcher deployment is discussed at length. Here we will only comment
that it is important to add the appropriate matcher package for your custom matcher to the
<matcherpackages> list and that the name of your matcher should not conflict with any of
the matchers described here.
|
|
|