Friday, April 29, 2011

Remove Event Listeners

Flex adds event listeners either inline (inside mx tags) or in functions inside script block.
The ways we remove added listeners for the event is same as the way we have added it.
i.e first, we need to call the removeEventListener on that component/container by passing all the parameters
which we passed while calling the addEventListener for the same component/container.
this may be just 2 required parameters as shown below:

comp_id.removeEventListener(eventType:EVENT_TYPE,removeHandlerFunction)

and then finally, we need to define the removeHandlerFunction which expects the same event type that we passed
as EVENT_TYPE in the above method and perform the logic there:

private function removeHandlerFunction(eventType:EVENT_TYPE):void {
....
}

But there is 1 difference in how the event listeners are removed.
If we have added any event listener inline (i.e. inside <mx:> tag for the component or container),
then even calling removeEventListener won't remove it.

However, all the events which are added through addEventListeners (inside script block) can be removed
using the removeEventListener

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createHandler(event)">
<mx:Script>
<![CDATA[
import mx.controls.Alert;

private function createHandler(event:Event):void {
b1.addEventListener(MouseEvent.CLICK,myClickHandler);
}

private function removeMyHandlers(event:Event):void {
Alert.show("Removing listener for Button 1");
/* Remove listener for b1's click event because it was added with the addEventListener() method */
b1.removeEventListener(MouseEvent.CLICK,myClickHandler);

/* Does NOT remove the listener for b2's click event because it was added inline i.e in MXML tag */
b2.removeEventListener(MouseEvent.CLICK,myClickHandler);
}

private function myClickHandler(event:Event):void {
Alert.show("The button was clicked");
}
]]>
</mx:Script>

<mx:Button id="b1" label="Click Me (Button 1)" />
<mx:Button id="b2" label="Click Me (Button 2)" click="myClickHandler(event)"/>
<mx:Button id="b3" label="Remove Event Listeners" click="removeMyHandlers(event)"/>
</mx:Application>


In the above example, first try to click button b1. You will see and Alert box saying "The button was clicked". Then, try same for Button b2. You will again see the same output.
Then, try to click the 'Remove Event Listeners' button. This button removes the event listener for b1
since it was added using the addEventListener. But for b2, it does not removes the event listener even though we called the b2.removeEventListener too.

After clicking on the third button, again try to click b1. The alert won't be displayed as it has already removed the listener for this button's click event and hence, it does not call myClickHandler.
However, b2 is still having its listener active and hence its click handler function myClickHandler executes and alert gets displayed on click on b2.

stopPropagation and stopImmediatePropagation

Generally, flex navigates its compelte display list, either upwards towards Application, in Bubbling or Target Phase
or downwards towards the immediate ancestor of the component/container which triggered the event in Capturing Phase.
However, we can stop this navigation or propagation using the following 2 methods of event:

1. stopPropagation: This is used to prevent the Event object from moving onto the next node, but allows the other event listeners (EVENT of same type, example another CLICK) on the current node to execute.
2. stopImmediatePropagation: This is used to prevent the Event object not only to move to next node, but it also does not allow the other event listeners (ONLY OF SAME TYPE, example another CLICK) on the current node to execute

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
click="clickHandler(event)" name="Application" initialize="initApp()">
<mx:Script>
<![CDATA[
import mx.controls.Alert;

private function initApp():void {
myBtn1.addEventListener(MouseEvent.CLICK,anotherClickHandlerForBtn1);
myBtn1.addEventListener(MouseEvent.CLICK,clickHandler);
myBtn1.addEventListener(MouseEvent.ROLL_OUT,rollOutHandler);
myBtn2.addEventListener(MouseEvent.CLICK,anotherClickHandlerForBtn2);
myBtn2.addEventListener(MouseEvent.CLICK,clickHandler);
myBtn2.addEventListener(MouseEvent.ROLL_OUT,rollOutHandler);
}

/*
This will always execute for the buttons
irrespective of stopPropagation or stopImmediatePropagation
as this is a ROLL_OUT event (Event other then CLICK type for which
we are calling the stopPropagation or stopImmediatePropagation)
*/

private function rollOutHandler(event:MouseEvent):void {
Alert.show("Roll Out event for target("+event.target.name+")&"+
" currentTarget("+event.currentTarget.name+")");
}


/*
In this function, we are calling stopPropagation.
So, Flex tries to see if there are any other event other than CLICK on this object or CLICK event itself on parent container. And if there are, it does not execute them
However, if there are more than 1 CLICK handlers for this button itself, it executes all of them. And do not move to the next node in event flow.
*/

private function anotherClickHandlerForBtn1(event:MouseEvent):void {
Alert.show("This is first click handler and would also allow all the other" +
" click handlers of this 'Button 1' to execute (event.stopPropagation)" +
" and stop propagating to other nodes ",event.type);
event.stopPropagation();
}

/*
In this function, we are calling stopImmediatePropagation
So, As soon as this CLICK handler gets executed, Flex stops the event there itself and
no other events gets called (even if there is another CLICK handler, it won't execute)
And also, it does not moves on to the next node in event flow.
*/

private function anotherClickHandlerForBtn2(event:MouseEvent):void {
Alert.show("This will just allow the click handler of this 'Button 2' to execute" +
" and then would stop propagating the event to other click handlers on same node" +
" as well as other nodes (event.stopPropagation)",event.type);
event.stopImmediatePropagation()
}

private function clickHandler(event:MouseEvent):void {
Alert.show("Target object: "+event.target.name
+"\n"+
"Phase: "+getPhaseName(event.eventPhase)
+"\n"+
"Current Target object: "+event.currentTarget.name);
}

private function getPhaseName(phase:uint):String {
switch(phase) {
case 1:
return "CAPTURING PHASE";
case 2:
return "TARGET PHASE";
case 3:
return "BUBBLING PHASE";
}
return "";
}
]]>
</mx:Script>
<mx:Panel borderThickness="250" name="Panel" click="clickHandler(event)" width="700" height="300">
<mx:VBox backgroundColor="#EEEEEE" click="clickHandler(event)" name="VBox" height="200" width="600"
horizontalAlign="center" verticalAlign="middle">
<mx:Label text="Stops propagation to next node but does not stops other events on the same node to execute" />
<mx:Button id="myBtn1" name="Button 1" label="Button 1" />
<mx:Label text="Stops propagation to next node as well as stops other CLICK events on the same node to execute" />
<mx:Button id="myBtn2" name="Button 2" label="Button 2" />
</mx:VBox>
</mx:Panel>
</mx:Application>

Capturing Phase Event

In Flex, we need to know what are the 'target' and 'currentTarget' properties of the Event object and also the
3 stages of Event processing. Let us go through them.

1. target and currentTarget properties: 'target' always refers to the component that has dispatched the event in
first place (example: Button component dispatching click event) and the 'currentTarget' refers to the container
which is currently handling the event (Example, VBOX container in which the above Button is placed and VBOX has
registered for listening to the Button's click event).

In Flex, there are 3 stages of Event processing:
1. Capturing Phase
2. Target Phase
3. Bubbling Phase

Consider the below example which has Application, inside which we have a Panel, inside which we have a VBOox and
then a Button Control.
So, the structure looks like this:

Application
Panel
VBox
Button

Say now, we have clicked on the button. This calls the 'click' event on button. Here, the 'target' object would
always be the same 'button'.

In Capturing Phase: Flex examies the Button's ancestors from the Application right down to the immediate ancestor
of the button (i.e. VBox in this case). This is hardly used. So, in this, the following steps occur during the
capturing phase in same order"
1. Check the Application container for click event listeners (target: Button, currentTarget: Application)
2. Check the Panel container for click event listeners (target: Button, currentTarget: Panel)
3. Check the VBox container for click event listeners (target: Button, currentTarget: VBox)

In Target Phase: Flex reaches the Button for seeing the listeners and here the 'target' and 'currentTarget' refers
to the same component i.e (target:Button, currentTarget: Button)

In Bubbling Phase: Flex examines the Button's ancestors for listeenrs. But here, it starts with the dispatcher's
(button's) immediate ancestor (VBox) and moves all up the display list to the root ancestor (i.e Application). This
is the reverse of the Capturing phase and most often used. The following steps occur in same order:
1. Check the VBox container for click event listeners (target: Button, currentTarget: VBox)
2. Check the Panel container for click event listeners (target: Button, currentTarget: Panel)
3. Check the Application container for click event listeners (target: Button, currentTarget: Application)


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
initialize="addCapturingPhaseEvent(event)" name="Application">
<mx:Script>
<![CDATA[
import mx.controls.Alert;

private function addCapturingPhaseEvent(event:Event):void {
/* to use capturing phase, we need to pass the "useCapture" parameter as true once
and false another time as the third parameter to the addEventListener method.
Passing "false" as the third parameter (Which is by default, but gets overridden if
we have passed as "true" once, will call the Bubbling as well as the Target phase
*/


Application.application.addEventListener(MouseEvent.CLICK,clickHandler,true);

// The below line if commented, will not call the bubbling and the target phase
// as we have set useCapture = true in the previous statement


Application.application.addEventListener(MouseEvent.CLICK,clickHandler,false);
myPanel.addEventListener(MouseEvent.CLICK,clickHandler,true);
myPanel.addEventListener(MouseEvent.CLICK,clickHandler,false);
myBtn.addEventListener(MouseEvent.CLICK,clickHandler,true);
myBtn.addEventListener(MouseEvent.CLICK,clickHandler,false);
myVBox.addEventListener(MouseEvent.CLICK,clickHandler,true);
myVBox.addEventListener(MouseEvent.CLICK,clickHandler,false);
}
private function clickHandler(event:MouseEvent):void {
Alert.show("Target object: "+event.target.name
+"\n"+
"Phase: "+getPhaseName(event.eventPhase)
+"\n"+
"Current Target object: "+event.currentTarget.name);
}

private function getPhaseName(phase:uint):String {
switch(phase) {
case 1:
return "CAPTURING PHASE";
case 2:
return "TARGET PHASE";
case 3:
return "BUBBLING PHASE";
}
return "";
}
]]>
</mx:Script>


<mx:Panel borderThickness="250" name="Panel" id="myPanel" width="500" height="300">
<mx:VBox backgroundColor="#EEEEEE" id="myVBox" name="VBox" height="200" width="300"
horizontalAlign="center" verticalAlign="middle">
<mx:Button name="Button" label="Click Me" id="myBtn" />
</mx:VBox>
</mx:Panel>
</mx:Application>

Bubbling And Target Event Phase

In Flex, we need to know what are the 'target' and 'currentTarget' properties of the Event object and also the
3 stages of Event processing. Let us go through them.

1. target and currentTarget properties: 'target' always refers to the component that has dispatched the event in
first place (example: Button component dispatching click event) and the 'currentTarget' refers to the container
which is currently handling the event (Example, VBOX container in which the above Button is placed and VBOX has
registered for listening to the Button's click event).

In Flex, there are 3 stages of Event processing:
1. Capturing Phase
2. Target Phase
3. Bubbling Phase

Consider the below example which has Application, inside which we have a Panel, inside which we have a VBOox and
then a Button Control.
So, the structure looks like this:

Application
Panel
VBox
Button

Say now, we have clicked on the button. This calls the 'click' event on button. Here, the 'target' object would
always be the same 'button'.

In Capturing Phase: Flex examies the Button's ancestors from the Application right down to the immediate ancestor
of the button (i.e. VBox in this case). This is hardly used. So, in this, the following steps occur during the
capturing phase in same order"
1. Check the Application container for click event listeners (target: Button, currentTarget: Application)
2. Check the Panel container for click event listeners (target: Button, currentTarget: Panel)
3. Check the VBox container for click event listeners (target: Button, currentTarget: VBox)

In Target Phase: Flex reaches the Button for seeing the listeners and here the 'target' and 'currentTarget' refers
to the same component i.e (target:Button, currentTarget: Button)

In Bubbling Phase: Flex examines the Button's ancestors for listeenrs. But here, it starts with the dispatcher's
(button's) immediate ancestor (VBox) and moves all up the display list to the root ancestor (i.e Application). This
is the reverse of the Capturing phase and most often used. The following steps occur in same order:
1. Check the VBox container for click event listeners (target: Button, currentTarget: VBox)
2. Check the Panel container for click event listeners (target: Button, currentTarget: Panel)
3. Check the Application container for click event listeners (target: Button, currentTarget: Application)

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
click="clickHandler(event)" name="Application">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
private function clickHandler(event:MouseEvent):void {
Alert.show("Target object: "+event.target.name
+"\n"+
"Phase: "+getPhaseName(event.eventPhase)
+"\n"+
"Current Target object: "+event.currentTarget.name);
}

private function getPhaseName(phase:uint):String {
switch(phase) {
case 1:
return "CAPTURING PHASE";
case 2:
return "TARGET PHASE";
case 3:
return "BUBBLING PHASE";
}
return "";
}
]]>
</mx:Script>
<mx:Panel borderThickness="250" name="Panel" click="clickHandler(event)" width="500" height="300">
<mx:VBox backgroundColor="#EEEEEE" click="clickHandler(event)" name="VBox" height="200" width="300"
horizontalAlign="center" verticalAlign="middle">
<mx:Button name="Button" label="Click Me" click="clickHandler(event)" />
</mx:VBox>
</mx:Panel>
</mx:Application>




In the above example, we have placed the click event handler on the containers (i.e Application, Panel, VBox) as well as the Button component
However, if you try to remove the click="clickHandler(event)" from any 1 container, say VBox, then on click of the VBox, you would find
that the Alert for the Bubbling phase with the currentTarget of Panel and Application gets displayed as they are checked in the bubbling
phase for the click event and since they have the handler for the click event, it gets called.
However, the Target phase of the VBox won't be called in this case as VBox does not handles the click event itself.

Monday, September 6, 2010

Conversion from/to between String and non String properties

Spring Custom Property Editors:

We might be wondering that even though the property of a bean if of any type (int, URL, Date etc), we always set the properties in the context file using the property attribute or constructor inside double quotes (" ") i.e. we always set the properties as String.
For example, if there is an age property of an employee and the property is of type int, then too, in the context file, the property for the employee bean is set as following:

<bean id="emp" class="com.blog.examples.employee">
<property name="age" value="25" />
</bean>


So, we see that the property is set within double quotes i.e. String. Similarly, consider this property wsdlDocumentUrl which we use for JaxRpcPortProxyFactoryBean for wiring Web Services:

<property name="wsdlDocumentUrl" value="http://www.mycompany.com/CustomService?wsdl" />


Though the wsdlDocumentUrl accepts a property of java.net.URL type, it is still specified with the String convention inside the context file. The Question is how does the property mapping happens from String to non-String specific types?

Well, under the covers, Spring automatically converts String value to the Specific type based on the Actual property type of the bean and this conversion happens through a feature of JavaBeans API known as PropertyEditor.
The java.beans.PropertyEditor interface provides a means to customize how String values are mapped to non-String types. A convinent implementation of this interface- java.beans.PropertyEditorSupport has 2 methods of interest to us:
1. getAsText() returns the String representation of a property's value
2 setAsText(String value) sets a bean property value from the String value passed in

If an attempt is made to set a non-String property to a String value, the setAsText() method is called to perform the conversion and Likewise, the getAsText() method will be called to to return a textual representation of the property's value.

Similarly, here are the Several PropertyEdiotors that Spring uses internally to convert the value of a property from a String to non-Strng specific type.
ClassEditor, CustomDateEditor, FileEditor, LocaleEditor, URLEditor etc

Bean Lifecycle using BeanFactory And ApplicationContext

The following is the lifecycle of bean in ApplicationContext and BeanFactory:

1. Instantiate: Spring Instantiates the bean
2. Populate Properties: Spring injects the bean proprties
3. Set bean name: If the bean implements BeanNameAware, Spring passes the bean's ID to the setBeanName() method
4. Set bean factory: If the bean implements BeanFactoryAware, Spring passes the bean's factory to setBeanFactory() method
5. Set Application Context: If the bean implements ApplicationContextAware, the setApplicationContext() method will be called. Note: This is the only extra step that comes in the lifecycle of a bean using ApplicationConetxt container instead of BeanFactory
6. PostProcess (Before initialization): If there are any BeanPostProcessors, Spring calls their postProcessBeforeInitialization() method (Example is PropertPlaceHolderConfigurer)
7. Initialize Beans: If the bean implements InitializingBean, its afterPropertiesSet() method will be called. If the bean has a custom init-method defined in context file, that specific initializing method will be called.
8. PostProcess (After Initialization): If there are any BeanPostProcessors, Spring calls their postProcessAfterInitialization() method
9. Bean ready to use: At this point of time, the bean is ready to be used by the application and will remain until it is no longer needed.
10 Destroy Bean: If the bean implements DisposableBean, its destroy() method will be called. However, If the bean has a custom destroy-method defined in context file, that specific method will be called.

Thursday, October 1, 2009

Quartz Scheduler with Spring

Spring and Quartz Scheduler:

We will take an example of sending the reminder of timesheet submission every Friday at 1:00 PM to all the employees using Quartz Scheduler:
Quartz Scheduler mainly uses the following 3 for implementing the job scheduling using spring:

1. JobDetailBean
2. CronTriggerBean
3. SchedulerFactoryBean
Let us see the role of each of them in detail:

JobDetailBean: JobDetailBean is simply a JavaBean representation of a JobDetail. JobDetail can be considered something whose objects contain all the information needed to run a Job. i.e. JobDetailsBean is a subclass of Quartz’s org.quartz.JobDetail, which requires the Job implementation be set through ‘jobClass' property. Let’s see how we configure a JobDetailBean in our context file:

<bean name="timsheetReminderJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.prokarma.TimeSheetReminderJob"/>
<property name="jobDataAsMap">
<map>
<entry key="timesheetServive" value-ref="timesheetService"/>
</map>
</property>
</bean>

And here is the TimeSheetReminderJob class which is declared above:

public class TimeSheetReminderJob extends QuartzJobBean {

private TimesheetService timesheetService;

/**
* Setter called after the TimesheetReminderJob is instantiated
* with the value from the JobDetailBean
*/
public void setTimesheetService(TimesheetService timesheetService) {
this.timesheetService = timesheetService;
}

protected void executeInternal(JobExecutionContext ctx)
throws JobExecutionException {
// do the actual work i.e. send timesheetRemiders
timesheetService.sendTimesheetRemiders();
}
}


As can be seen from the bean declaration and the TimeSheetRemiderClass, We have configured a bean named as ‘timeSheetReminder’ as a JobDetailBean. The properties of this bean are very important to understand. 'jobClass' property specifies which class will act as a job (In this case, TimeSheetReminderJob) and hence run. This class should extend QuartzJobBean and implement the method executeExternal which contains the business logic that should be implemented for the job (in this case, sending timesheet reminders by calling sendTimeSheetRemider() method form it). The jobDataAsMap’ property takes a java.util.Map that contains properties that are to be set on the object specified by the jobClass (Since, we have just 1 property ‘timeSheetService’, we set it and give it a ref to another bean somewhere defined in the context file.

CronTriggerBean: Now, since the job is created, we need to specify when this job should run (In our case, as we said earlier, we need it to run every Friday at 1:00 PM). This is specified through org.quartz.Trigger class. There are 2 implementation of Trigger class. They are SimpleTriggerBean and CronTriggerBean. Using SimpleTriggerBean, we can just specify how often a job should run and (optionally) how long to wait for the job to run for the first time (i.e. after the context startup). Here we cannot specify inner details like the exact day/date/month/year etc and exact time on which it should run. Hence, we opted for CronTriggerBean as our Trigger for our TimeSheetReminderJob and specify the exact date and time for the job.
Here is how we configure the CronTiggerBean as a bean in our context file:

<bean id="cronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="timesheetReminderJob"/>
<!-- run every Friday at 1 PM -->
<property name="cronExpression" value="0 0 13 ? * FRI"/>
</bean>


As can be seen, we just need to set 2 properties for the CronTriggerBean. They are: jobDetail (which specifies the JobDetailBean we declared earlier i.e. which specifies the class which acts as a job) and ‘cronExpressionProperty’ which specifies a expression that identifies the runtime of a job. It can be broken upto six (or possibly seven) time elements, separated by spaces. In order from left to right, these elements are defined as follows:

1. Seconds (0-59)
2. Minutes (0-59)
3. Hours (0-23)
4. Day of month (1-31)
5. Month (1-12 or JAN-DEC)
6. Day of Week (1-7 or SUN-SAT)
7. Year (1970-2099)


Each of these elements can be specified with an explicit value (eg. 6), a range (ex: 9-12), a list (eg. 9,10,11) or a wildcard (eg. *). The day of the month and day of the week are mutually exclusive, so you should specify just one of those fields by specifying the other field as a blank (i.e. a ‘?’)
In the case of our cronTriggerBean, we’ve set the cronExpression as “0 0 13 ? * FRI”. You can read this as “Zeroth second of 0th minute of 1 PM (13:00 in 24hrs format is 1:00 PM ) on any day of the month of any month and every Friday of the week”. Some examples of cron expressions and their meanings are specified below:

0 0 10,14,16 * * ? Every day at 10AM, 2PM and 4PM
0 0,15,30,45 * 1-30 ? Every 15 minutes on the first 30 days of the month
30 0 0 1 1 ? 2012 30 seconds after midnight on Jan 1, 2012
0 0 8-17 ? * MON-FRI Every Monday to Friday from 8AM to 5PM

SchedulerFactoryBean: To start a Quartz’s job, we will use Spring’s SchedulerFactoryBean. It is declared as:

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerBean"/>
</list>
</property>
</bean>

The triggers’ property takes an array of references to trigger beans. Since we only have a single trigger at the moment, we simply need to wire it with a list containing a single reference to the cronTriggerBean bean.
This was the final step in setting up the Quartz scheduler in Spring. At this time, our timesheet reminder service will be calling sendTimesheetRemiders() menthod on every Friday at 1 PM.