The HTTP POST is received by the built-in receiver, which in turn fires a fileUpdateevent and places data about the file system change into the global context.. Listing 10.10 File Kicker C
Trang 1from the receiverUrlvalue in the event handler The next thing to note is that the map may
only consist of string values The kicker does not perform any object morphing and will balk if
not presented with all proper strings Finally, we have the kick method itself We’ve surrounded it
by logger statements including timestamps The kick method holds until the POST has either
completed successfully or fails after the defined number of retries and delay times Therefore, in
theory at least, the kick method could take a fair amount of time to complete The issue you could
run into is that if your timer ticks occur faster than the kick method under failure/retries, you
could easily end up with an ever-growing stack of kicks attempting to fire concurrently As a
gen-eral rule of thumb, ensure that your timer tick delay is greater than the number of retries times the
max retry delay time This will keep you out of this sticky mess
Let’s take a mental trip over to the receiving application for a moment, forgetting that it’s
actually residing within the same application on this sample As you can see in the kicker event
configuration, we are calling ”/resources/kickReceiver”, which in this sample is another
groovy script, shown in Listing 10.8 All we are doing here is dumping out the various parameters
we received
Listing 10.8 /resource/kickReceiver.groovy
def onCreate() {
logger.INFO{"Got kicked by: " + zget("/request/params/appName") }
logger.INFO{"Parameters found: " + zlist("/request/params") }
zlist("/request/params", false).each{ key ->
logger.INFO{">> " + key + ": " + zget("/request/params/${key}") }
}
}
The log output is shown in Listing 10.9 We can see the two expected parameters that we
supplied to the kick method, but we also see two extra parameters that were provided that tell us
the kicker and the application name that originated the kick
Listing 10.9 Log Output of /app/resources/kickReceiver.groovy
2009-09-01 21:22:18 app.resources.kickReceiver.groovy::onCreate
Thread-2
INFO [ Got kicked by: Book.Async.SimpleKicker ]
2009-09-01 21:22:18 app.resources.kickReceiver.groovy::onCreate
Thread-2
INFO [ Parameters found: [/request/params/appName,
/request/params/arg1, /request/params/kickerName,
/request/params/number1] ]
2009-09-01 21:22:18 app.resources.kickReceiver.groovy::onCreate
Thread-2
Trang 2INFO [ appName: Book.Async.SimpleKicker ]
2009-09-01 21:22:18 app.resources.kickReceiver.groovy::onCreate
Thread-2
INFO [ arg1: Test message ]
2009-09-01 21:22:18 app.resources.kickReceiver.groovy::onCreate
Thread-2
INFO [ kickerName: myKicker ]
2009-09-01 21:22:18 app.resources.kickReceiver.groovy::onCreate
Thread-2
INFO [ number1: 234 ]
That’s about all there is to the simple kicker Next, we’ll go over some slightly more advanced
kickers that can help us check files and mailboxes and work with message queuing systems
File Kicker and Receiver
A file kicker/receiver is built into WebSphere sMash This built-in kicker/receiver gives your
application the opportunity to respond to changes in the file system The file kicker periodically
examines the file system and sends an HTTP POST request when the specified element in the file
system has changed The HTTP POST is received by the built-in receiver, which in turn fires a
fileUpdateevent and places data about the file system change into the global context
Applica-tion logic to respond to the event should be placed in the fileUpdateevent handler To set up
the file kicker, we need to modify the zero.config file to add the file kicker timer handler In
Listing 10.10, we configure the file kicker to watch ”c:/zero/fileKicker/file1”whenever
this file is modified; the service defined in the receiverURLwill be called
Listing 10.10 File Kicker Configuration
/config/handlers += [{
"events" : "timer",
"handler" : "zero.file.kicker.FileKicker.class",
"conditions" : "/event/_taskName =~ myFileKicker",
"instanceData" : {
"fileName" : "C:/zero/fileKicker/file1",
"receiverURL" : http://localhost:8080/file/FileReceiver
}
}]
Next, we need to configure the file receiver that will handle the HTTP POST sent by the file
kicker We demonstrate this in Listing 10.11
Trang 3Listing 10.11 File Receiver Configuration
/config/handlers += [{
"events" : "POST",
"handler" : "zero.file.receiver.FileReceiver.class",
"conditions" : "/request/path =~ /file/FileReceiver(/.*)?"
}]
The receiver is configured to handle any HTTP POST event that is sent to the
FileReceiver in the file virtual directory When an HTTP POST is made to this path, the
receiver is activated and then fires a fileUpdateevent for which we need to configure a handler
To configure a handler for this event, we can do as shown in Listing 10.12
Listing 10.12 File Update Event Handler Configuration
/config/handlers += [{
"events" : "fileUpdate",
"handler" : "FileUpdateHandler.groovy"
}]
As you can see, the FileUpdateHandler.groovy is configured to respond to the
fileUpdate event The FileUpdateHandler.groovy file should be placed in our
app/scriptsdirectory In this file, the onFileUpdatemethod will be called when the event is
triggered by the file receiver In this method, we need to put whatever application logic is needed
to appropriately respond to the file being updated In our case, we’ll just print out the data that is
returned from the receiver to the info logger, as seen in Listing 10.13
Listing 10.13 File Update Event Handler
def onFileUpdate(){
def kickData = zget("/event/kickData")
logger.INFO {"kickData="+kickData}
}
As you can see, the data from the kicker is received by the receiver and placed in the
”/event/kickData”global context entry This entry contains a variety of information, such as
when the file was updated, the filename that was updated, the name of the kicker, and so on See
the output of our event handler in Listing 10.14
Trang 4Listing 10.14 File Update Event Handler Output
2009-10-01 04:43:24 app.scripts.FileUpdateHandler.groovy::onFileUpdate
Thread-11
INFO [ kickData=[
fileData:[fileName:C:/zero/fileKicker/file1,
msg:file found, lastModified:1254244143625],
fileName:C:/zero/fileKicker/file1,
appName:fileKicker,
kickerName:myFileKicker] ]
So, to go over the course of events once again, the file is updated, which activates the file
kicker The file kicker is a timer that watches a particular file or directory The file kicker calls the
file receiver, which converts the POST data from the kicker into a global context entry and then
generates a fileUpdateevent This event is handled by our FileUpdateHandler.groovy,
which outputs the data into the info log file As you can see, this enables us to create a great many
file-oriented handlers with just a few lines of configuration and whatever code you need to handle
the file changes
Events
WebSphere sMash has several built-in events for requests We’ve created handlers for GET and
POST requests in this and previous chapters There are also events that surround every GET,
PUT, POST, and DELETE request Those built-in events let you execute code before a request
and after a request, and log when a request has been serviced To hook into these events, we
simply need to configure handlers for the specific events For demonstration purposes, we’ll
cre-ate a handler that handles all three of these events and logs a message The events are named
requestBegin, log, and requestEnd Listing 10.15 shows how to configure a handler for all
of these events
Listing 10.15 Configure Event Handlers for the requestBegin, log, and requestEnd Events
/config/handlers += [{
"events" : "requestBegin",
"handler" : "LogEvent.groovy",
"conditions" : "/request/path =~ /foo(/.*)?"
}]
/config/handlers += [{
"events" : "log",
Trang 5"handler" : "LogEvent.groovy",
"conditions" : "/request/path =~ /foo(/.*)?"
}]
/config/handlers += [{
"events" : "requestEnd",
"handler" : "LogEvent.groovy",
"conditions" : "/request/path =~ /foo(/.*)?"
}]
Notice that we’ve defined the same handler for all three events We can do this because each
event will call its own on<EventName>method Note also that we’re restricting our handlers to
firing only when we execute something in the /foopath You can modify this condition to be any
particular path or any path if desired We create the LogEvent.groovy handler in the
app/scriptsdirectory with the code shown in Listing 10.16
Listing 10.16 LogEvent.groovy Handler to Handle Several Events
def onRequestBegin(){
logger.INFO {"onRequestBegin"}
def tmp = zget("/event/_name")
logger.INFO {"/event/_name="+tmp}
}
def onLog(){
logger.INFO {"onLog"}
def tmp = zget("/event/_name")
logger.INFO {"/event/_name="+tmp}
}
def onRequestEnd(){
logger.INFO {"onRequestEnd"}
def tmp = zget("/event/_name")
logger.INFO {"/event/_name="+tmp}
}
The code in Listing 10.16 handles all three events with the onRequestBegin, onLog, and
onRequestEndmethods All we’re doing in this demonstration is logging to the info logger, but
we do access the event zone of the global context to retrieve the event name We could also access
any of the other event zone properties for the fired event Just to be complete, the logged output of
Trang 6Listing 10.17 LogEvent.groovy Handler Output
2009-10-01 16:14:41 app.scripts.LogEvent.groovy::onRequestBegin
Thread-11
INFO [ onRequestBegin ]
2009-10-01 16:14:41 app.scripts.LogEvent.groovy::onRequestBegin
Thread-11
INFO [ /event/_name=requestBegin ]
2009-10-01 16:14:42 app.scripts.LogEvent.groovy::onLog Thread-11
INFO [ onLog ]
2009-10-01 16:14:42 app.scripts.LogEvent.groovy::onLog Thread-11
INFO [ /event/_name=log ]
2009-10-01 16:14:42 app.scripts.LogEvent.groovy::onRequestEnd Thread-11
INFO [ onRequestEnd ]
2009-10-01 16:14:42 app.scripts.LogEvent.groovy::onRequestEnd Thread-11
INFO [ /event/_name=requestEnd ]
As we can see, the requestBeginevent is fired, followed by the log event and finally the
requestEndevent This all assumes there is some sort of handler behind /foo—for example, an
HTTP GET handler One thing to note is that these events can be configured and handled by
mul-tiple handlers For example, you may have a couple of different log event handlers: One could log
accesses to a local log, and another could call a remote logging application to record live statistics
about your application However, the HTTP GET, PUT, POST, and DELETE events may only
have one handler In the next section, we take a look at custom events, which enable you to extend
the cast of events to couple together your handlers with events of your choosing
Custom Events
WebSphere sMash provides a complete event infrastructure for loosely coupling handlers As we
saw in the “File Kicker and Receiver” section, a fileUpdateevent was fired by the file receiver
and handled by another handler This gives advanced developers tremendous flexibility and
extensibility of WebSphere sMash by allowing developers to add their own event types and
con-figuring multiple handlers to listen for those events Let’s write a resource that kicks off an event
of its own and a couple of handlers to handle the event To start with, we’ll write an HTTP GET
handler named Foo.groovyin Listing 10.18
Listing 10.18 Foo.groovy HTTP GET Event Handler
import zero.core.events.EventEngine
def onGET() {
logger.INFO {"scripts/Foo onGET called"}
Trang 7def eventData = ["fooData": "value, could be a map of data"]
EventEngine.fire("foo", eventData);
}
Foo.groovygoes into the scriptsdirectory We start by importing the EventEngine
class, which gives us the ability to fire events For our new event, we create some event data
called fooDatathat will be the payload we’ll retrieve in our event handlers The event we’re
fir-ing is called ”foo”and is fired by calling the EventEngine.firemethod This is all kicked off
by the built-in HTTP GET event We configure our Foo.groovyhandler to be triggered when
the /foopath is called, as can be seen in the configuration in Listing 10.19
Listing 10.19 Foo Event Configuration
/config/handlers += [{
"events" : "GET",
"handler" : "Foo.groovy",
"conditions" : "/request/path =~ /foo(/.*)?"
}]
/config/handlers += [{
"events" : "foo",
"handler" : "FooHandler.groovy"
}]
/config/handlers += [{
"events" : "foo",
"handler" : "FooHandlerTwo.groovy"
}]
When the request path has /fooin it, the Foo.groovyhandler is triggered, which in turn
fires the fooevent The fooevent is then handled by two other handlers that we have configured:
FooHandler.groovyand FooHandlerTwo.groovy When these two handlers are triggered,
the onFoomethod in each is executed For the purpose of our example, they both simply log to
the info logger, as shown in Listing 10.20
Listing 10.20 Foo Event Handler Code
FooHandler.groovy:
def onFoo(){
logger.INFO {"onFoo invoked for FooHandler"}
def fooData = zget("/event/fooData")
Trang 8logger.INFO {"fooData="+fooData}
}
FooHandlerTwo.groovy:
def onFoo(){
logger.INFO {"onFoo invoked for FooHandlerTwo"}
def fooData = zget("/event/fooData")
logger.INFO {"fooData="+fooData}
}
Both fooevent handlers have access to the payload data and can act on it accordingly
Finally, if we hit the /fooURL of our application, we’ll see what’s listed in Listing 10.21
Listing 10.21 Foo Event Output
2009-10-01 15:39:37 app.scripts.Foo.groovy::onGET Thread-11
INFO [ scripts/Foo onGET called ]
2009-10-01 15:39:37 app.scripts.FooHandler.groovy::onFoo Thread-11
INFO [ onFoo invoked for FooHandler ]
2009-10-01 15:39:38 app.scripts.FooHandler.groovy::onFoo Thread-11
INFO [ fooData=value, could be a map of data ]
We see that we handle the HTTP GET event and generate our fooevent, which is handled
by a couple of different handlers Don’t forget that you can have at most one handler for GET,
PUT, POST, and DELETE events, but custom events and the other built-in events allow multiple
handlers to be defined So, using an HTTP GET handler to generate a custom event would allow
you to use multiple handlers for every GET event
Conclusion
We covered a variety of ways to communicate and process data asynchronously The manner in which these
events occur is based largely on the situation and reliability requirements of your application We hope that
this chapter has provided you with the tools needed to expand the capabilities of your application through
the use of a variety of built-in and custom timers, kickers, and events
References
For more information on setting up SSL, refer to the following resources:
For IBM Java key management using the Ikeyman tool, refer to
http://download.boulder.ibm.com/ibmdl/pub/software/dw/jdk/security/50/GSK7c_SSL_IKM_Guide.pdf
Trang 9For Sun’s keytool utility, refer to http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide
html#CreateKeystore
For another good resource for defining a secure environment using key stores, see the “Using the Java Secure
Socket Extension in WebSphere Application Server” article from the IBM WebSphere Developer Technical
Journal by Messaoud Benantar at
http://www.ibm.com/developerworks/websphere/techjournal/0502_benan-tar/0502_benantar.html
While we are providing references to more information on SSL, see the following articles for IBM at http:/
/www.ibm.com/developerworks/java/jdk/security/50/secguides/jsse2Docs/JSSE2RefGuide.html, and from
Sun at http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html
Trang 10251
In this chapter, we introduce some WebSphere sMash components that are useful, if not
neces-sary, for developing robust WebSphere sMash applications We touch on these components only
to make you aware that they are there for you to use We encourage you to seek more information
in the product documentation for the components that you find most useful in your application In
particular, we touch on URIUtils (which are used to create URIs that reference your WebSphere
sMash application), validators (which assist in validating cached content), and Active Content
Filtering (which helps to secure your site against cross-site scripting) Finally, we introduce
Assemble Flow, which allows nonprogrammers to create conversation applications in
Web-Sphere sMash
URIUtils
URIUtils are a set of cross-language utility methods for creating relative and absolute URIs for
your application These URIs can be used to create references to images, cascading style sheets,
hyperlinks, and other page resources within your application Generally, you should use relative
URIs so that they are robust enough to survive the rigors of security and client-side manipulation
such as reverse proxy servers and mashups
We look at the particulars of each language in turn to reveal any nuisances between them
and learn what the API can do to help you with your application development
Java APIs
To get access to the URIUtils class, you’ll need to import it:
import zero.core.utils.URIUtils;
Framework
Components