Then, for each process you want to execute, add a timer task entry and event handler into the zero.config file... When the task ticks, it fires a “timer” event, and sets the event task name
Trang 1Listing 9.15 Application Code to Call a Secured Service
def callDataService( args ) {
logger.INFO {"Starting with: ${args}"}
def URL = "https://crownjewels.acme.com/resources/${args.service}"
if ( args.id ) {
URL += "/${args.id}
}
args.remove('service')
args.remove('id')
args.eachWithIndex() { it, idx ->
URL += (idx == 0 ? '?' : '&' ) +
URLEncoder.encode(it.key, "UTF-8") + "=" +
URLEncoder.encode(it.value, "UTF-8")
}
logger.INFO {"URL: ${URL}"}
def response = Connection.doGET(URL)
def doc = new XmlParser().parse( response.responseBody )
logger.INFO {"Results : ${doc}"}
return doc
}
In this example, we make a dynamic call to some service as defined by the method
parame-ters, and receive an XML document as a response It is a big assumption that we will be receiving
an XML response, but this serves for this example If you are expecting a response other than
XML, adjust the response handler to process the correct data type
Let’s examine this bit of reusable code a little more In the first several lines, we build up
the base URL The static part of that URL should really be defined as an entry in the application
config file, and not a static string as shown in this example
We supply the actual service to be called in the args.service entry, and if supplied, we add
on the resource ID
Next, we remove the service and ID entries from the argument map, and then walk the
remain-ing args and append them to the URL as parameters Encodremain-ing the parameters is necessary because
the parameters might include characters that are not transmittable in their original encoding
Finally, we open a GET connection to the URL and pull in the results as an XML
docu-ment There is a lot more we could do to improve this method, such as dynamically handling
dif-ferent response data formats, but at least you should be able to see how easy it is to make secure
connection calls to remote services
Download from www.wowebook.com
Trang 2Conclusion
In this chapter, we have taken a whirlwind tour of various security subsystems within the
Web-Sphere sMash environment There is a lot we didn’t cover about various configuration options
within each security scenario The documentation provided on the Project Zero website goes
deeper into the security details The goal of this chapter was to give you the basics needed to
cre-ate a secure WebSphere sMash application The information learned in this chapter is directly
usable in real-world applications
Trang 3This page intentionally left blank
Download from www.wowebook.com
Trang 4In this chapter, we discuss a variety of WebSphere sMash capabilities and provide an insight as to
when you can use these features to add greater flexibility to your application For instance, there
are often times when an application cannot simply rely on the standard request/response cycle
dictated by the user’s browser You may want to perform some preparation work upon application
initialization and not force the first user in to bear the brunt of the extra processing delay There
may be times where you want your application to periodically check in with another server, pull
in news feeds, or send usage statistics to a monitoring site The scenarios are limitless and may
not fall within the normal traffic patterns of your users
WebSphere sMash provides several features to assist you in processing data based on
vari-ous events These events can be regular and cyclical in nature, where a timer can initiate an event,
or you may need to watch a file system for changes and process those files There are also
facili-ties for watching POP mail accounts for new mail, and queues can receive asynchronous
mes-sages as part of the Reliable Transport Extension (RTE)
A large network of connected applications can also use WebSphere sMash to communicate
without any users or browsers being involved in the mix This opens the door to a wide array of
internetworked applications that can stay in contact with each other
Timers
A timer is used to fire re-occurring events The timer ticks at predetermined intervals, and a
han-dler event method called onTimer()can then take any required actions
To use timers, you need to add the zero.timer dependency to the application’s ivy.xml file
Then, for each process you want to execute, add a timer task entry and event handler into the
zero.config file By convention, you should place your timer handler scripts into a directory
C H A P T E R 1 0
Event Processing
Trang 5called /app/scripts/timers This is just a recommendation; you can organize your code as
you see fit
In the configuration snippet shown in Listing 10.1, we define a timer named “heartbeat,”
which fires every 30 seconds, and call the onTimermethod of the /app/scripts/timers/
heart-beat.groovy file In the first line, we define the timer task A timer task is an object that has a
single property called a “delay,” or the tick time in seconds When the task ticks, it fires a “timer”
event, and sets the event task name to the ending name of the timer task, which in our sample is
“heartbeat.” For every timer task, there is a corresponding handler block The handler block
con-sists of an events type of timer, with conditions matching the event’s task name to the timer’s task
name The handler determines the script to call for the doTimermethod The instanceData
member contains a map of arguments that are passed into the onTimermethod
Listing 10.1 Timer Configuration
/config/timer/tasks/heartbeat = { "delay" : 30 }/config/handlers += [{
"events" : "timer",
"conditions" : "/event/_taskName =~ heartbeat",
"handler" : "timers/heartbeat.groovy",
"instanceData" : {
"myArg1" : "someConfigurableValue"
}
}]
So, what do we put into our doTimermethod? Well, that can basically be whatever you want
The instanceDatavariables are accessible from the “event” global context So, in our sample
configuration, the doTimermethod can grab the instance data using zget(“/event/myArg1”)
Listing 10.2 shows our handler code located in the file: /app/scripts/timers/heartbeat.groovy
Listing 10.2 /app/config/timers/heartbeat.groovy
package timers
def onTimer() {
logger.INFO{"Heartbeat timer fired"}
logger.INFO{"Event name: " + zget("/event/_taskName")}
logger.INFO{"Event Instance Data MyArg1 : " + zget("/event/myArg1") }
}
Start the application, and let’s see what we get produced to the console Nothing Hmm,
even waiting 30 seconds, and we get nothing The reason for this is that the timer is not fired
until a request comes into the ZSO, which then actually starts up the application So, use your
Download from www.wowebook.com
Trang 6browser to access the application (http://localhost:8080) The browser displays the normal sMash
“up and running” page, whereas the console log shows our logging output We can take away a
few things from this test First, timers by default start only when the ZSO has activated the
appli-cation, and by consequence, they also stop firing when the ZSO idles the application We’ll
address this seemingly erratic behavior momentarily The other thing to notice on this little
sample is that a timer event fires immediately when the application is initialized, and then upon
each tick’s delay value This can be used to our advantage for using a timer to perform a one-time
application initialization
By default, the timer will not start until the first request comes in and the ZSO initiates the
application If you need the timer to start as soon as the application initializes, set the following in
the zero.config; the timer fires immediately and then at the defined intervals:
/config/zso/immediateStart=true
By default, the ZSO starts an application when a request comes in on one of the listening
ports At this point, ZSO starts the application and subsequently the timer service After a period
of inactivity, ZSO closes down the application and therefore the timers that are running within
that application If you set the ZSO immediateStartflag, ZSO immediately starts the
applica-tion and allows the timer to fire Depending on the delay time of the timer, the ZSO may still shut
down the application, but the timer(s) continues to fire at the appropriate intervals, forcing the
ZSO to bring the application back up into listening mode
Application Initialization Using Timers
One common use of a timer is to perform a one-time application initialization As stated earlier, a
timer is fired immediately upon application startup and then at each delay interval So, to force an
application to perform a single startup, set the delay time to a very large value It will fire one
time, and remain dormant thereafter The only issue to resolve is to ensure that initialization has
completed before any user requests are processed When the application is run under the ZSO,
this race condition is even more likely The solution is to use an initialization flag
When a request comes into the ZSO for an application, the ZSO starts up the application,
which immediately fires the timer event The timer event and the servicing of the request happen
in parallel, which means that each entry point or starting page of the application needs to check
for initialization before continuing and actually servicing the request Let’s go through a quick
example of using an initialization flag
First, create a new inittimer, with a delay time of 9999999 (or any ridiculously large
value) and an event handler stanza, as shown in Listing 10.3 A value this large (~3 years) will
ensure that our timer never fires again This is essentially the same as our first example, but this
time, we are not defining any instanceDatavalues
Trang 7Listing 10.3 Initialization Timer Configuration
/config/timer/tasks/init = { "delay" : 99999999 }
/config/handlers += [{
"events" : "timer",
"conditions" : "/event/_taskName =~ init",
"handler" : "timers/init.groovy"
}
The /app/scripts/timers/init.groovy::onTimermethod shown in Listing 10.4
performs whatever initialization processes our application requires In this sample, we just put the
thread to sleep for several seconds to simulate some rather long database activity After the
ization has completed, we set an application-level context flag to indicate that we are fully
initial-ized and ready to accept incoming requests This is all well and good, but what if a request comes in
before our flag is set? We need to create a blocking method that holds the request(s) until the
appli-cation is initialized This is represented in the ”waitForInitialized”method This method
simply enters a time-delayed loop waiting for the proper initialization flag to be set Although it is
probably not a great practice to sleep your request threads, it can come in handy in this situation
Listing 10.4 /app/scripts/timers/init.groovy
package timers
def onTimer() {
try {
if ( ! zget("/app/initialized") ) {
logger.INFO{ "Initializing application - " +
"from timer task (${event._taskName[]})" }
Thread.currentThread().sleep(30000) // 30 sec
zput( "/app/initialized", true )
logger.INFO{ "Initialization completed." }
}
} catch ( e ) {
logger.SEVERE{ "Initializing error - ${e}" }
}
}
def waitForInitialized() {
def x = 0
while ( ! app.initialized[] ) {
logger.INFO{ "Waiting for initialization to complete ${++x}" }
Download from www.wowebook.com
Trang 8Thread.currentThread().sleep(1000) // 1 sec
}
return true
}
The only thing we have left to do is to add the call to our waitFormethod in each
pos-sible web page of the application We show a sample of this in Listing 10.5, showing us a simple
index.gt file Although this sort of waiting for initialization process becomes cumbersome to
manage if there are many potential entry pages into your application, it does solve a rather
thorny issue
Listing 10.5 /public/index.gt
<% invokeMethod("timers/init.groovy", "waitForInitialized", null ) %>
<html>
<head>
<title>Init Test</title>
</head>
<body>
<h1>Hello!</h1>
</body>
</html>
Test out our initialization process by starting the application and quickly attempting to
access the main page The browser should be forced to wait several seconds before the ready flag
is set and the rendering is permitted to continue Check the log file to verify that the proper
sequence of events has taken place
There are other ways that you can explore to gain both a functional application
initializa-tion and still maintain the benefits of using ZSO to manage overall applicainitializa-tion resources One
entails having a dedicated “timer” application that is always running and firing events This
assumes that the initialization is for more generic resources, such as databases, file systems, or
other remote resources The timer application can also “kick” other applications and delivery
information at regular intervals We discuss kickers in the next section If you have a cluster of
related applications on a single host, organizing timed events around a single long-running
“timer” application can solve a lot of issues with the individual applications running cyclical
events, while still allowing the ZSO to manage the other application instances
Kickers
There are several different styles of kickers that we cover in this chapter The purpose of a kicker
Trang 9Table 10.1 Common Kicker InstanceData Members
InstanceData
Configuration Members
Description
receiverURL The target URL to receive the “kick” notification This is a
required variable for all kickers Despite its name, you may also use a connection name instead of an actual URL for this field
maxRetries The number of times to attempt to kick the remote application
The default is five retries
maxDelay This is the delay time between failed kick attempts The default
is 5 seconds between retries
map This is typically used to supply the username and password under basic authentication connections This is an options setting based on your requirements
has been made, or the number of configured retries has been exceeded Kickers use the timer
sub-system discussed previously to perform a kick, or test for conditions that will invoke a kick
action The kick call returns either success or failure based on the status code returned from the
POST call to the remote application
To enable kicker support in your application, you need to add the appropriate zero.kicker
module into the ivy.config There are a few new instanceDatavariables that go into the event
stanza for each type of kicker, which we need to define in the configuration file Other kicker
types also have their own instanceDatavariables, which we’ll point out shortly The variables
that are shared among all kickers are shown in Table 10.1 We’ll look at sample configurations for
each kicker
As a matter of consistency and convention, it is recommended that you place all kicker
han-dlers under the ”/app/scripts/kickers” Of course, you are free to place them wherever
makes sense to you and your application structure
Simple Kicker
The most basic kicker simply calls a handler on each timer tick, passing in the variables defined
in the instanceDatablock from the configuration file It’s simply a matter of calling the kick
function from your custom handler This will perform a POST to the designated receiverUrl,
passing in a map of the parameters passed into the kick method
Let’s build a simple kicker to illustrate this concept and look at what the receiving
applica-tion delivered First, add the ”zero.kicker”module to the ivy.config file Next, create a timer
Download from www.wowebook.com
Trang 10and event stanza in your application’s configuration file, as shown in Listing 10.6 Remember that
timers will not fire when the application is idled by the ZSO, so make sure you set the
immediateStartflag to true
Listing 10.6 Simple Kicker Configuration
/config/zso/immediateStart=true /config/timer/tasks/myKicker = { "delay"
: 120 }
/config/handlers += [{
"events" : "timer",
"conditions" : "/event/_taskName =~ myKicker",
"handler" : "kickers/mySimpleKicker.groovy",
"instanceData" : {
"receiverUrl": "http://localhost:8080/resources/kickReceiver"
}
}]
We create a standard timer with a two-minute tick delay, and a corresponding handler that
calls ”mySimpleKicker.groovy”, which is shown in Listing 10.7 Notice how we define the
receiverUrl Under normal circumstances, this would point to a different application, likely
residing on a different host For this sample, we’ll just call a resource in the same application
Listing 10.7 /app/scripts/kickers/mySimpleKicker.groovy
import zero.kicker.Kicker
def onTimer() {
def args = [
"arg1": "Test message",
"number1" : "234"
]
logger.INFO{ System.currentTimeMillis() +
": mySimpleKicker: sending: " + args }
def kickOk = Kicker.kick( args );
logger.INFO{ System.currentTimeMillis() +
": mySimpleKicker: kickOk: " + kickOk }
}
There is actually a lot to inspect in this little bit of code First, we import our Kicker class,
which contains several variations of the kick()method This simplest and most common class
accepts a map of arguments to be sent to the remote host The URL is automatically retrieved