Writing an External Processor
In this tutorial we build an external processor that only allows events through that are in the
southern hemisphere. Then we refine it so that the user can specify the latitude below which
events are acceptable. All of the code is in the externalExample
directory in the SOD distribution
and the recipe files are in recipes
.
Writing the processor class
The first step is to create a class that SOD will invoke to check for the proper latitude. Each subsetting or processing step in SOD has a corresponding Java interface that defines its operation. Check the external types document to see which step is appropriate for the operation you wish to perform. Since we want to check on the properties of an earthquake(origin in DHI terms) our class should implement the interface OriginSubsetter. The only requirement for an Origin subsetter is that it implement one method:
public StringTree accept(EventAccessOperations eventAccess, EventAttr eventAttr, Origin preferred_origin) throws Exception;
An implementation that checks for origins in the southern hemisphere is given below.
package edu.sc.seis.sod.example; import edu.iris.Fissures.IfEvent.EventAttr; import edu.iris.Fissures.IfEvent.Origin; import edu.sc.seis.fissuresUtil.cache.CacheEvent; import edu.sc.seis.sod.status.Fail; import edu.sc.seis.sod.status.Pass; import edu.sc.seis.sod.status.StringTree; import edu.sc.seis.sod.subsetter.origin.OriginSubsetter; public class SouthOMatic implements OriginSubsetter { public StringTree accept(CacheEvent eventAccess, EventAttr eventAttr, Origin preferred_origin) { if(preferred_origin.getLocation().latitude > 0) { return new Fail(this, "origin not in the southern hemisphere"); } return new Pass(this); } }If this SouthOMatic is listed in your recipe, SOD instantiates an instance of it and calls accept on it for every origin that passes through with the arguments eventAccess, eventAttr and preferred_origin describing the origin. Depending on the returned StringTree, SOD does further processing of the origin or stops at this point. StringTree is an abstract class that encapsulates a SOD processing result. For a simple processing steps like ours, we can use the two simplest subclasses of StringTree, Pass and Fail. Pass and Fail are both created with the subsetter as the first argument so SOD can log what subsetter performed the action. If an optional String reason is given this is also logged. As you can see we check if the event's preferredOrigin has a latitude greater than 0. If so, we return an instance of Fail and SOD will stop processing the origin. Otherwise we return Pass and things continue from this point.
Adding your external processor to a recipe
To get SOD to instantiate and use your new external processor you must add it to a recipe file. This is done with an externalOriginSubsetter ingredient for our reciple like so:
<externalOriginSubsetter> <classname>edu.sc.seis.sod.example.SouthOMatic</classname> </externalOriginSubsetter>
The name for any external processor ingredient is always external followed by the name of the interface you've implemented. Then the first element inside the external element is a classname element with the fully qualified classname of the processor you've written. SOD uses reflection to find your class and instantiate it.
Compiling your processor
The final step to get the external processor to run is to compile the processor and add it to SOD's runtime
classpath. To simplify this, we've included a
Maven 1 project that handles getting all of the dependencies together and compiling
any external processors located in externalExample/src
. So the first step is to
download and
install Maven 1. Once you've got it setup, you can test the installation
by going into externalExample
and running maven jar
. This should produce lots of messages about downloading
jars and compiling classes and will eventually make a jar file and place it at externalExample/target/sodExternals-3.2.9.jar
. This jar is already included in the classpath of the SOD scripts so you should be able to run sod -f externalExample/recipes/southOMatic.xml
and see the origins south of the equator scroll by.
Customizing the processor from the recipe
In addition to the accept method, you may also add a constructor that takes a DOM Element in any external processor.
If SOD sees this on an external, it'll pass in an org.w3c.dom.Element
representing the external element from the recipe.
This allows you to extract any extra
configuration information out of the recipe that you need. With this we can make the maximum latitude
configurable instead of always 0. Here is a variation of the SouthOMatic, LatOMatic, that does this. SOD
includes a helper class, DOMHelper, that makes it easy to pull values out of the XML Element. Here we us the extractFloat method. Notice that we
give a default value in case the recipe file does not contain a maxLat element. The default value is optional, but if it is not given and the
recipe does not have that value then an exception will be thrown.
package edu.sc.seis.sod.example; import org.w3c.dom.Element; import edu.iris.Fissures.IfEvent.EventAttr; import edu.iris.Fissures.IfEvent.Origin; import edu.sc.seis.fissuresUtil.cache.CacheEvent; import edu.sc.seis.fissuresUtil.display.configuration.DOMHelper; import edu.sc.seis.sod.status.Fail; import edu.sc.seis.sod.status.Pass; import edu.sc.seis.sod.status.StringTree; import edu.sc.seis.sod.subsetter.origin.OriginSubsetter; public class LatOMatic implements OriginSubsetter { public LatOMatic(Element el) { maxLat = DOMHelper.extractFloat(el, "maxLat", 0); } public StringTree accept(CacheEvent eventAccess, EventAttr eventAttr, Origin preferred_origin) throws Exception { if(preferred_origin.getLocation().latitude > maxLat) { return new Fail(this, "origin not below " + maxLat + " latitude"); } return new Pass(this); } float maxLat; }
<externalOriginSubsetter> <classname>edu.sc.seis.sod.example.LatOMatic</classname> <maxLat>45</maxLat> </externalOriginSubsetter>
The only changes needed from southOMatic.xml
are the new classanme and the addition of the maxLat element.
If you run sod -f externalExamples/recipes/latOMatic.xml
you can see that the events printed out are
now at latitude 45 or below.