Using Selenium to test JSF (myFaces impl) application

I have been looking for a good way to do integration testing of webapplications done in JSF, and decided to give Selenium a try.
First I had a look at the Selenium IDE, it is basically a Firefox “record” tool that remembers the actions you do in the webapp, and then saves these actions as a test-template for you to use later on. But I didn’t want to limit myself to any browser, and I would also like to keep an opening for some continous build processes and frameworks. I therefore decided to go for Selenium Remote Control (Selenium RC), which also allows me to write the tests in java.

I know that Selenium recommends using TestNG instead of JUnit (JUnit should be considered a unit testing tool, not for integration testing) , but since I had some (moderate) experience with JUnit from before I decided to go for this. So I downloaded Selenium RC, and created a new java-project in Eclipse with selenium-java-client-driver.jar, selenium-server.jar and junit.jar in my lib-folder. Both selenium-java-client-driver.jar and junit.jar should be added to the build path, but there’s no need to add selenium-server.jar.

Before you run your tests the selenium server needs to be running, and you can manually start this from command-line by running the command “java -jar selenium-server.jar”. But then, you might want to add some options or specify some properties, and perhaps you don’t want to start messing around with the cmd-window at all. So I created an ant-task for starting and stopping the server. This task I can then set as dependency in another task that runs my tests, but this is of course up to you.

The start task:

	<target name="selenium-start">
		<java jar="${lib.test.dir}/${selenium-jar}" fork="true" spawn="true">
			<arg  line="-port ${selenium.port}" />
			<arg  line="-debug" />
			<arg  line="-log ${build.dir}/selenium.log" /> 		
		</java>
	</target>

The stop task:

	<target name="selenium-stop" description="Stop the Selenium RC server on port ${selenium.port}">
		<get taskname="selenium-shutdown" dest="${build.dir}/selenium.log" src="http://localhost:${selenium.port}/selenium-server/driver/?cmd=shutDown" ignoreerrors="true" />
	</target>

So, what about the testing?

If you’re familiar with JUnit, you know that you need to define the setUp() and tearDown() method. Selenium have created a class SeleneseTestCase that extends TestCase of JUnit, and this class is giving you some selenium-utilities which can be nice to have. I decided to create my tests extending the SeleneseTestCase, but you don’t have to – you can extend TestCase directly. Also, to avoid having to specify the setup() and tearDown() method in all my test-cases I created an abstract class called DefaultTest which I would extend for my test-cases. The DefaultTest has this definition:

public abstract class DefaultTest extends SeleneseTestCase
{
	protected Selenium browser;
	public static final String DEFAULT_TIMEOUT = "20000";
	public static final String BROWSER_FIREFOX = "*firefox";
	public static final String BROWSER_CHROME = "*chrome";
	public static final String BROWSER_IE = "*iexplore";
	
	public void setUp() throws Exception
	{
		browser = new DefaultSelenium("localhost", 6666, BROWSER_CHROME, "http://localhost/Test/");
		browser.start();
	}

	public void tearDown() throws Exception
	{
		browser.stop();
	}
}

To create the “virtual” browser object in Selenium you need to specify the server-host, which port to use, which browser to simulate and so on. I’m doing my tests against a local jboss-server running on port 8080. Note that jboss uses the default port of Selenium (4444), so I specified 6666 for my selenium server to run.

To be able to simulate a user typing something or pressing links, it’s obvious that we in the java-code need some way of locating the different web-elements. In Selenium this is referred to as “locators,” in java you specify them as String objects. You can locate an element in different ways, I mention some of them here:

  • By id: String locator = “id=theIdOfMyComponent”;
  • By name: String locator = “name=theNameOfMyComponent”;
  • By xpath: String locator = “xpath=//table[@id=’myTable’]/tbody/tr/td[2]/span/a”;
  • By link content: String locator = “link=ClickMe”;
  • By table-cell-refernce (TableId.Row.Cell): String locator = “myTable.1.0”;
  • By DOM: String locator = “dom=document.forms[‘myForm’].myElement”;

To start with something simple, we can try a TestCase for logging on to an application. As a convention to follow all the methods in your test-cases should start with “test”, like testLogin():

public class LoginTestCase extends DefaultTest
{
	public final void testLogin()
	{
		String userNameLocator = "name=username";
		String passwordLocator = "name=password";
		String componentLocator = "id=idOfTheComponentIExpectToBeThereAfterSuccessfullyLoggingIn";
		
		browser.open("http://localhost:8080/MyWebbAppContextRoot/");
		browser.type(userNameLocator, "myUsername");
		browser.type(passwordLocator, "myPassword");
		browser.click("id=submitButton");
		browser.waitForPageToLoad(DEFAULT_TIMEOUT);
		assertEquals("The title I expect", browser.getTitle());
		assertTrue(browser.isElementPresent(componentLocator));
		
	}
	
}

You run the test by right-clicking the class (run all tests in the class) or individually on each method -> select Run As -> select JUnitTest. Of course this can also be done from an ant task.

The browser.open() specifies the initial page that should be loaded in the browser. Then you can see that we fill in a value for the username and password, and click a button. Whenever there is a click that requires a page reload, you have to follow that command by a “browser.waitForPageToLoad()”. I set my standard timeout to 20 sec (20000ms), but if the response is sent earlier the browser acts upon it immediately. Then we do an assertion on the title of the page we were sent to, as well as an assertion to check that an expected component on this page actually exist. So, this is a testCase that tests for a successful logon. Another test that could be done is for example to pass invalid username/password, to see that unsuccessful logons are handled correctly.

Testing your webapp like this is integration testing, not unit testing. It is therefore likely that to be able to do your test you need to other actions first, like you follow a chain of commands; you might have to log on, maybe click a link to go on the proper page, or you need to do some other actions before you can do your assertions. Thus, I created some static methods in a utility-class that handles the most common operations, so that I can reuse those from my TestCases. Consider a class like this:

public class InteractionUtil extends DefaultTest
{
	public static void login(Selenium browser)
	{
		String userNameLocator = "name=username";
		String passwordLocator = "name=password";
		
		browser.open("http://localhost:8080/MyWebbAppContextRoot/");
		browser.type(userNameLocator, "myUsername");
		browser.type(passwordLocator, "myPassword");
		browser.click("id=submitButton");
		browser.waitForPageToLoad(DEFAULT_TIMEOUT);
	}
}

Then, my testLogin() method would simply be like this:


	public final void testLogin()
	{
		String componentLocator = "id=idOfTheComponentIExpectToBeThereAfterSuccessfullyLoggingIn";
		InteractionUtil.login(browser);
		assertEquals("The title I expect", browser.getTitle());
		assertTrue(browser.isElementPresent(componentLocator));
	}

And it is very easy to also include this logon-action in other testCases where it is needed. All actions you need to do often can go into such a utility-class.

As a final example I will show how to use the JsCookMenu of tomahawk library from Selenium. I struggled quite a bit with this one before I was able to make the action trigger. Since triggering an element in a dropdown-menu like this can be considered a “generic” action I include it in my utility-class:


	public static void clickJsCookMenu(Selenium browser, String theme, String jsCookId, String itemValue)
	{
		String fieldRowLocator = "xpath=//div[@id='"+jsCookId+"']/div/table/tbody/tr[@class='"+theme+"MenuItem' and td = '"+itemValue+"']";
		String jsCookMenuTdLocator = "xpath=//div[@id='"+jsCookId+"']/table/tbody/tr/td[@class='"+theme+"MainItem']";
		String fieldRowHoverLocator = "xpath=//div[@id='"+jsCookId+"']/div/table/tbody/tr[@class='"+theme+"MenuItemHover']";
		String fieldRowActiveLocator = "xpath=//div[@id='"+jsCookId+"']/div/table/tbody/tr[@class='"+theme+"MenuItemActive']";
		
		browser.mouseOver(jsCookMenuTdLocator);
		browser.waitForCondition("selenium.isVisible(\""+ fieldRowLocator+"\");", DEFAULT_TIMEOUT);
		browser.mouseOver(fieldRowLocator);
		browser.mouseDown(fieldRowHoverLocator);
		browser.mouseUp(fieldRowActiveLocator);
	
		browser.waitForPageToLoad(DEFAULT_TIMEOUT);
	}

To explain a bit, I pass as parameters the browser object, the jsCook theme being used (office, ie and so on), the id I’ve given the jscookMenu component in my jsp and the value/text of the item I want to click. I first do a mouseOver to display the menu, and notice the “waitForCondition” command that follows. This means that the browser should wait for the menu to be visible. Then i figured out I needed to do a mouse-over on the row holding the item. This makes the css class change, so I do mouseDown on the “hovered” row. But the mouseDown-event in the jsCook javascript doesn’t trigger the link, actually a mouseUp does, so finally I do a mouseUp-event on the active row. And of course I then wait for the page to reload.

Then from my test-method I can simply do:


	public void testJsCookMenu()
	{
		InteractionUtil.login(browser);
		UserInteractionUtil.clickJsCookMenu(browser, "ThemeIE", "myJsCookId", "theElementIWantToClick");
		//--- assertions ---
	}

I hope this post will give you a brief understanding on how to use Selenium for testing your webapps!

Mod_gzip – how to make configuration work for Apache 1.3, mod_jk and JBOSS/JSF

I’ve been working a couple of days trying to get mod_gzip to work with apache 1.3, enabling compression for JSF application (.faces). Everything seemed so easy in the configuration described here, but I actually troubled quite a lot with it, and wanted to share what I’ve learned. ๐Ÿ™‚ I used this page as a starting point for my digging into mod_gzip. I use mod__jk to forward the request to jboss’ tomcat server.

Firs and most important of all, the configuration I use that make things work with JSF:

LoadModule gzip_module     libexec/mod_gzip.so

<IfModule mod_gzip.c>
mod_gzip_on                   Yes
mod_gzip_can_negotiate        Yes
mod_gzip_static_suffix        .gz
AddEncoding              gzip .gz
mod_gzip_update_static        No
mod_gzip_command_version      '/mod_gzip_status'
mod_gzip_temp_dir             /tmp
mod_gzip_keep_workfiles       No
mod_gzip_minimum_file_size    300
mod_gzip_maximum_file_size    500000
mod_gzip_maximum_inmem_size   60000
mod_gzip_min_http             1000
mod_gzip_handle_methods        GET POST
mod_gzip_dechunk              Yes
mod_gzip_send_vary            On

#Files and items to compress
mod_gzip_item_include         file       \.html$
mod_gzip_item_include         file       \.htm$
mod_gzip_item_include         file       \.js$
mod_gzip_item_include         file       \.js
mod_gzip_item_include         file       \.faces
mod_gzip_item_include         file       \.css$
mod_gzip_item_include         file       \.jsp$
mod_gzip_item_include         file       \.jsp

mod_gzip_item_include         uri        \.jsp$
mod_gzip_item_include         uri        \.jsp

mod_gzip_item_include         handler    \.*
mod_gzip_item_include         handler    \.*$

mod_gzip_item_include         mime       ^text/html$
mod_gzip_item_include         mime       ^text/html
mod_gzip_item_include         mime      ^text/plain
mod_gzip_item_include         mime      ^text/plain$
mod_gzip_item_include         mime       ^text/xml$
mod_gzip_item_include         mime       ^text/css$
mod_gzip_item_include         mime       ^text/javascript$
mod_gzip_item_include         mime       ^text/javascript
mod_gzip_item_include         mime       ^application/x-javascript$
mod_gzip_item_include         mime       ^application/javascript$

CustomLog                     logs/mod_gzip.log common_with_mod_gzip_info2
LogFormat                     "%h %l %u %t \"%V %r\" %<s %{Content-type}o  %b mo
d_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n -< Out:%{mod_gzip_output_
size}n = %{mod_gzip_compression_ratio}n pct." common_with_mod_gzip_info2
</IfModule>

I will just say (cause it is important) that without the two lines including the “handler” patterns, I couldn’t get any compression to work when I was playing with JSF applications. All the logging lines had status “DECLINED:EXCLUDED”.

The first thing to do when you’re supposed to do this would be to enable logging of gzip to understand what is going on. Then based on status-codes you can get a clue to why a file is compressed or not.

Add the following line in your conf:
LogFormat “%h %l %u %t \”%V %r\” %<s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n -< Out:%{mod_gzip_output_size}n = %{mod_gzip_compression_ratio}n pct.” common_with_mod_gzip_info2

A problem that troubled me were when I got prints like this:
213.162.235.138 – – [21/Aug/2008:15:13:44 +0200] “localhost.localdomain GET /Url/css/styles.css HTTP/1.1” 200 text/plain 0 mod_gzip: SEND_AS_IS:NO_200 In:0 -< Out:0 = 0 pct.

Apache reports the file as 200, but gzip ends up with status code “SEND_AS_IS:NO_200”. Ok, so we go to check the meaning of the status codes, but that didn’t tell us much. Confusing? It really means that this file is cached in the browser, and will not be compressed because of this. Try ctrl+F5 to clear the cache, then it should compress that file as well.

Also, even if I included the line “mod_gzip_item_include file \.js$” to compress javascript, for all the javascripts it reported “SEND_AS_IS:RESPONSE_CONTENT_TYPE_EXCLUDED”
I troubled with this one, but then I remembered something I read on the internet: “The order of processing during each of both phases is not important, but to trigger the compression of a request’s content this request a) must match at least one include rule in each of both phases and # b) must not match an exclude rule in any of both phases.”

In other words, for some reason it didn’t find an include rule for javascript in both phases. I had included mime type ^text/javascript, so I couldn’t understand this. But I felt like navigating blindly, cause I never saw what mime-type the request was. So I added the following to my log statement: “%{Content-type}o” – which would print out the mime-type as well. Then I saw that for some javascripts the mime-type were application/x-javascript. I included this in the include-list as well, then case was closed ๐Ÿ™‚

Hope this post will help others in the same situation, or at least it might give you a clue to what is going on ๐Ÿ™‚

Ajax ReRendering – How to reRender part of your page in Myfaces using Richfaces

If you read this post I assume you have a general knowledge about what Ajax is, and what capabilities lies within. As a web-developer, there might be times where you would like to not do a full submit of your page, but you would actually like to just update a small part of the page. An application that achieves this gives the user a more “desktop-application”-like experience, and it will mostly also be a saver when it comes to performance, as you only load a part of the page – as well as the data going to be displayed in it.

For Myfaces, both 1.1 and 1.2 specification, there is a component library named RichFaces. The components there are nice to use for adding ajax-features to your application, and there are also possibilities of adding those capabilities to non-ajax components in myFaces or Tomahawk libraries.

You can download the libraries from here: RichFaces. Depending on the version of Myfaces you use, you need to get different RichFaces version. For MyFaces 1.1 core you need the RichFaces 3.1.X libraries, for Myfaces 1.2 core you can get the 3.2.X libaries. The 3.2.X libraries does NOT support Myfaces version 1.1

Then, to make use of the new library you need to add the following to your web.xml:

    <filter>
        <display-name>RichFaces Filter</display-name>
        <filter-name>richfaces</filter-name>
        <filter-class>org.ajax4jsf.Filter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>richfaces</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>

On the top of your jsps you need to include the taglibraries by inserting these lines:
<%@ taglib uri=”http://richfaces.org/rich&#8221; prefix=”rich”%>
<%@ taglib uri=”https://ajax4jsf.dev.java.net/ajax&#8221; prefix=”a4j”%>

So, when it comes to the actual reRendering of components or part of your page, there are several different ways of doing this.

In its simplest form, you can use the a4j:support to add ajax capabilities to ordinary myfaces components. In this example we use it on an inputText. You set the event property (javascript events), give the id of the component(s) you want to reRender, and then you go. Everytime a user releases a key, the reRender will be called, and getting the outText component again:

<h:inputText id="myInput" value="#{myBean.myProperty}">
    <a4j:support event="onkeyup" reRender="outText"></a4j:support>
</h:inputText>

<h:outputText id="outText" value="#{myBean.myProperty}"></h:outputText>

If you use componentBindings, and create those components programmatically, you need to do your custom modification of that component in the setter-method of this component to let the reRendering work. Let’s say you have a panelGrid, and you create it java-side and add two outPutTexts to it. If the value of those outputTexts change, and you want to reRender the panelGrid to display this, then the setter of this component is invoked as long as the getter returns null. So you should do like this:

Jsp:

<h:inputText id="myInput" value="#{myBean.myProperty}">
    <a4j:support event="onkeyup" reRender="outPanel"></a4j:support>
</h:inputText>

<t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>

Java:

public HtmlPanelGrid getHtmlPanelGrid()
{
    return htmlPanelGrid;
}

public void setHtmlPanelGrid(HtmlPanelGrid htmlPanelGrid)
{
    //Clean exisiting children
    htmlPanelGrid.getChildren().clear();

    //Add your modifications
    htmlPanelGrid.getChildren().add(createOutputText("out1","#{myBean.myProperty1}"));
    htmlPanelGrid.getChildren().add(createOutputText("out2","#{myBean.myProperty2}"));

    this.htmlPanelGrid = htmlPanelGrid;
}

private UIComponent createOutputText(String id, String valueBinding)
{
    HtmlOutputText out = new HtmlOutputText();
    out.setId(id);
    ValueBinding vb = FacesContext.getCurrentInstance().getApplication().createValueBinding(
    valueBinding);
    out.setValueBinding("value", vb);

    return out;
}

It is also possible to create the a4j:support programmatically, like this:

HtmlAjaxSupport ajaxSupport = new HtmlAjaxSupport();
ajaxSupport.setEvent("onchange");
ajaxSupport.setId("ajaxSupport");
ajaxSupport.setFocus("myForm:theIdOfComponentIWantToFocusOnAfterAjaxSubmit");
ajaxSupport.setReRender("myForm:idOFComponentIWantToReRender"); 

myUiComponent.getChildren().add(ajaxSupport);

There is also a component that creates a javascript-function for you which you can use to pass properties to your bean, execute actions and finally reRender components. It’s called a4j:jsFunction. Let’s say I have a h:commandButton, and when I click it I want to set a value to a property in my bean, I want to run an action, and then display the results. I could have done this with an t:updateActionListener, but then I would have been forced to do a full submit of the whole page. Instead, I can do it like this:


    //Define javascriptFunction with parameter
    <a4j:form>
        <a4j:jsFunction name="setParameterAndRerender" action="#{myBean.action}" reRender="outPanel" >
             <a4j:actionparam name="param1" assignTo="#{myBean.myProperty1}"  />
         </a4j:jsFunction>
    </a4j:form>

    <t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>

    <h:commandButton value="Click me" onclick="setParameterAndRerender('MyValue');return false;"></h:commandButton>

Notice that I set return false in the onclick of the commandButton to avoid it from submitting. I’ll let ajax handle that.

If you create the a4j:support-object progammatically, I’ve experienced that it doesn’t always find the id of the component you have specified to reRender. To solve this, you can use a combination of this one and the javascript function just described:

HtmlAjaxSupport ajaxSupport = new HtmlAjaxSupport();
ajaxSupport.setEvent("onchange");
ajaxSupport.setId("ajaxSupport");
ajaxSupport.setFocus("myForm:theIdOfComponentIWantToFocusOnAfterAjaxSubmit");

//We don't specify reRender id here, but set a javascript function to run when completed
//ajaxSupport.setReRender("myForm:idOFComponentIWantToReRender");
ajaxSupport.setOncomplete("setParameterAndRerender('MyValue');");

myUiComponent.getChildren().add(ajaxSupport);

So, what about the RichFaces library? In all components the ajax capabilities are included, you don’t have to use a4j:support. When using one of the components the submit will always be an ajax submit, so you can just specify which components to reRender. As a short example, instead of using a h:commandButton you can use a4j:commandButton, like this:

    <a4j:commandButton value="Click me" action="#{myBean.action}"  reRender="outPanel"/>
    <t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>

Also, if you have a part of a page that always should be ajaxRendered, and you are tired of of writing Ids to reRender, simply wrap that part of the page inside an a4j:outputPanel and set the ajaxRendered property to true. In my a4j:commandButton, I don’t have to set the reRender property as this panel is now always reRendered by ajax submits:


    <a4j:commandButton value="Click me" action="#{myBean.action}" />

    <a4j:outputPanel ajaxRendered="true">
        <t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>
    </a4j:outputPanel>

I hope this have given you a brief idea of what is possible to do with ajax/richFaces and also how to do it ๐Ÿ™‚

I suggest you to check out the livedemo page to see all the different components that RichFaces give you: Live demo

Migration guide – go from Myfaces 1.1.X to Myfaces 1.2.3

If you are currently using Myfaces 1.1.X and want to start to use Myfaces core 1.2.3, there are certain steps you need to do and to be aware of to be able to make your existing 1.1.X-version application run. JSF 1.2 requires java 1.5 or later, JSP 2.1, JSTL 1.2 and a Java Servlet 2.5 implementation. If you use Jboss, this means that you have to go for jboss version 4.2.2 or higher (supports java5).

  1. First of all you need to download the new Myfaces-1.2 Core libraries, you can do it from here: Myfaces Project
  2. If you have been using Myfaces 1.1.X, you have probably also been using javax.servlet.jar and javax.servlet.jsp.jar. But the 1.2.3 version requires JSP 2.1, JSTL 1.2 and Java Servlet 2.5, so you need to update those libraries. The libraries you want to get are jsp-api-2.1.jar, jstl-1.2.jar and servlet-api-2.5.jar. You can get them from here: Jboss repository.
  3. The libraries are now in place. But you will find out that several classes and methods that existed in Myfaces-1.1.5 are now deprecated. For example, ValueBinding is now ValueExpression, and MethodBinding is MethodExpression. I will give you the different way in creating these programmatically, the way it is with 1.1.5, and the way it should be done in 1.2.3. Note that for ValueExpressions it is necessary to pass the “expected” class as parameter – meaning that if your ValueExpression would be used in the “value” property, the class would probably be java.lang.String. If it was to be used in a “rendered” property, the class should be java.lang.Boolean. If you don’t do this properly you would normally get a class cast exception, or at least some strange results: ValueBinding – 1.1.5
    ValueBinding vb = FacesContext.getCurrentInstance().getApplication().createValueBinding(
                        "#{myBean.myProperty}");
    myComponent.setValueBinding("value", vb);
    

    ValueExpression- 1.2.3

    FacesContext context = FacesContext.getCurrentInstance();
    ValueExpression vex = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), "#{myBean.myProperty}", String.class);
    myComponent.setValueExpression("value", vex);
    ValueExpression rex = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), "#{myBean.myProperty}", Boolean.class);
    myComponent.setValueExpression("rendered", rex);
    

    MethodBinding – 1.1.5

    MethodBinding methodBinding = FacesContext.getCurrentInstance().getApplication().createMethodBinding(
    			"#{myHandler.action}",null);
    myComponent.setAction( methodBinding );
    

    MethodExpression – 1.2.3

    FacesContext context = FacesContext.getCurrentInstance();
    MethodExpression methodEx = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(),
    			"#{myHandler.action}", String.class, new Class[] {});
    myComponent.setActionExpression(methodEx );
    

    ActionListener – 1.1.5

    try
            {    Class[] parameterList = { Class.forName("javax.faces.event.ActionEvent") };
                MethodBinding actionListenerBinding = FacesContext.getCurrentInstance().getApplication().createMethodBinding(
                    "#{myHandler.myListener}",parameterList);
                myComponent.setActionListener(actionListenerBinding );
            }
            catch (Exception e)
           {
                log.error("error setting ActionListener");
            }
    

    ActionListener – 1.2.3

    FacesContext context = FacesContext.getCurrentInstance();
    ELContext elContext = context .getELContext();
    MethodExpression actionListenerExpression = context.getApplication().getExpressionFactory().createMethodExpression(
    elContext,"#{myHandler.myActionListenerMethod}",null,new Class[] {ActionEvent.class});
    
     MethodExpressionActionListener methodExpressionActionListener = new MethodExpressionActionListener(actionListenerExpression);
    
  4. Also rememeber that the tld respects the html 4 specification, so old attribiutes like align, alt, background and color are deprecated. You need to update these and set proper css instead.

Good luck!

Refresh parent window from child window – conditional reloading with javascript and AJAX

If you work with popups, there will be situations where you need the parent window to update based on some changes/submitted values in the popup window. I will show a solution that is done for myfaces/jsf, and it’s based on the ‘onload’ event of the popup window. I also use ajax (a4j implementation) to update the parent window to avoid a submit and full screen refresh there.

The basic conceptual thoughts about this are quite easy: When you submit a form – or do other actions in your popup that sends data to the server, you need to update the parent window. It could be that you in the popup for example added an item to a table that are displayed in your parent window. So, when you click your button or link in the popup that fires of an action or submit of some sort, you also trigger a javascript on the onclick event that retrieves a hidden button in your parent window and cliks it. This would cause a submit /refresh on you parent window, and the new data that you added from the popup is diplsayed.

Popup.jsp: The popup form with submit button and onclick event:


<h:form id="myPopupForm">
                <t:commandButton id="mySubmit" action="#{myHandler.myAction}" onclick="updateParentWindow();" value="#{messages.myMessage}" >
                </t:commandButton>
</h:form>

Parent.jsp: The parent window hidden button that submits the form or in other ways (onclick event) refreshes that page

<h:form id="updateParentForm" >
        <t:commandButton style="display: none; visibility: hidden;" id="updateParentButton" action="#{myHandler.myAction}"></t:commandButton>
 </h:form>

The script that finds the parent button and clicks it

function updateParentWindow()
{
    var elementToGet = "updateParentForm"+ ":" + "updateParentButton";

    var form = document.forms['updateParentForm'];

    var button = form.elements[elementToGet];

    button.click();
}

But then, if we do it like this – what are the guarantee that the action we fired off in the popup is finished before the parent view is refreshed? None. If we do a submit in the popup, that page will reload. During reloading there is an onload-event that is called, and the popup is not reloaded until the action we fired off has finished. In other words, putting the function inside the onload-event is safe, it will never refresh the parent window before the submit you did is completed. So, let’s move the call of the updateParentWindow()-function from the button to the onload-event of the popup-page:Popup.jsp

<f:verbatim>
    <body onload="updateParentWindow();">
</f:verbatim>

If you now try your application you should se that if you submit the popup, as soon as it has reloaded, your parent window will refresh as well. Nice! This is one big step in the right direction. But there are still some issues to deal with. If I open my popup-window for the first time, I don’t want my parent window to refresh, cause I haven’t done any changes to the data in my popup yet. Having the updateParentWindow() call in the onload event as it is in the example abowe would cause the parent window to be refreshed also the first time the window opens.We want to avoid this, therefore we add some knowledge that the onload event should only trigger the function if the popup page was reloaded by some clicks/submit in the popup-page itself. What we do is to add a boolean value in javascript somewhere inside the body (not the head) of the parent page. It defaults to false, but the links/buttons in the popup will call a small function that set’s this property to true. Then we do a conditional test in the onload event, and only continue if this value is true.The javascript boolean inside the body of the parent page:Parent.jsp

<f:verbatim>
    <script type="text/javascript">
        var fromPopup = false;
    </script>
</f:verbatim>

Our links and buttons in the popup will on the onclick-event set this property to true:Popup.jsp


<h:commandLink onclick="window.opener.fromPopup = true;" action="#{myHandler.myAction}">
        <h:outputText value="myAction"></h:outputText>
</h:commandLink>

And then the conditional reloading would be like this:


<f:verbatim>
    <body onload="if(window.opener.fromPopup)updateParentWindow(); window.opener.fromLink = false;">
</f:verbatim>

It is important to notice that we have to reset the boolean window.opener.fromLink whenever the popup reloads, but we need to do it AFTER the test.

If you are pleased by this solution, no further steps are necessary! But in my application I display a lot of data at the same time, and what I updated in my popup is only a small part of the view in the parent window. Therefore I only wanted to refresh that part of the page, not do a full refresh/reload of my parent window.To do this I use the a4j:commandButton, which has ajax-capabilities and gives me the possibility of rerendering only a part of the page. If you remember we had a hidden button in our parent window that when clicked was responsible for refreshing that page. We modify it a bit, and create an a4j:commandButton instead, and add the reRender property to update the view:Parent.jsp

<a4j:form id="updateParentForm" >
		<a4j:commandButton style="display: none;" id="updateParentButton"  reRender="myComponentOutsideAForm" ></a4j:commandButton>
</a4j:form>

Notice that the area/component I decide to rerender is given by it’s id. Rerendering a component inside a form will fail in Firefox, you will get an error message in the console saying “f has no properties,” and all cliks on links from this point would not work. So either you would have to go for the ordinary submit/refresh, or you can only update areas of the page that doesn’t contain forms. So, applying this code, if you now trigger your submit in the popup page you will se that when it reloads it updates the parent window, but only the part you specified in the ajax-function we created. Avoiding a full refresh gives a better user experience as well as it saves you from retrieving data from the server more than necessary.

Then, what about form validation? Whether you use application validation (business-logic validation in your action methods), or you use the builtin jsf conversion/validation options, or both, it should be possible to handle this as well. If we click a link or button, but the validation fails, we don’t want to update the parent window. This can be done by adding a boolean on the top of our popup.jsp, as well as using this boolean in our updateParentWindow function. Whenever we do an action from the popup, this boolean must be set. If it is business logic validation, it would be easy to set a property if not all requirements are met. If you use the builtin conversion/validation in jsf, you can use the FacesContext.getMessages() to do this. In the popup.jsp, everytime it loads, we get the boolean from our backing bean and pass it on to the javascript. This would avoid the parentWindow to be updated if validation fails.

First, modify the script we use to update parent to respect a boolean parameter:

function updateParentWindow(validationFailed)
{
    if(validationFailed)
	return;
    else
   {
    var elementToGet = "updateParentForm"+ ":" + "updateParentButton";

    var form = document.forms['updateParentForm'];

    var button = form.elements[elementToGet];

    button.click();
   }
}

In the handler we need a boolean property that we can set depending on whether the validation failed or not. We create a private method that will help us to set this boolean, the important thing is that we call it from all our action methods. So the handler might look something like this:

public class MyHandler
{
    private boolean validationFailed = false;

    //Action
    public void doSomething()
    {
        ...
        Some code/business logic
        ...

        If some business logic/validation is not correct, pass this on to the validation method
            setValidation(true);
        If business logic/validation is correct
            setValidation(false);

    }

    private void setValidation(boolean applicationValidationFailed)
    {
        FacesContext context = FacesContext.getCurrentInstance();
        Iterator<FacesMessage> messages = context.getMessages();
        if(messages.hasNext() || applicationValidationFailed)
            setValidationFailed(true);
        else
            setValidationFailed(false);
    }
}

Then on top of our popup jsp inside <% %> tags we retrieve the handler, and we store the boolean property inside a local variable:

<%

MyHandler myHandler = (MyHandler)FacesContext.getCurrentInstance().getApplication ().
getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(),"myHandler");
boolean validationFailed = myHandler.isValidationFailed();
%>

And then we also modify the onload of this page to pass the boolean to the javascript:


<f:verbatim>
    <body onload="if(window.opener.fromPopup)updateParentWindow(<%= validationFailed %>); window.opener.fromLink = false;">
</f:verbatim>

Done! Your popup-page should also respect the validation now, and not update the parent if it fails.

I hope that this example will be helpful, and if not completely adaptable to your requirements it might lead you into the right path. I end this post by showing the popup.jsp and the parent.jsp in whole, to make it easier for you to see what I’ve tried to explain:Parent.jsp

<f:view  >
    <t:document>
    <t:documentHead>
    ...
    </t:documentHead>

    <f:verbatim>
    <body>
    </f:verbatim>

  <f:verbatim>
    <script type="text/javascript">
    //Used in popup
    var fromLink = false;
    </script>
    </f:verbatim>            

    Some content
    ...

    ...

    <h:panelGrid id="myComponentOutsideAForm">
        THIS AREA/CONTENT WILL BE REFRESHED
    </h:panelGrid>

    <a4j:form id="updateParentForm" >
        <a4j:commandButton style="display: none;" id="updateParentButton"  reRender="myComponentOutsideAForm" ></a4j:commandButton>
   </a4j:form>  

<f:verbatim>
    </body>
</f:verbatim>

</t:document>

</f:view>

Popup.jsp

<f:view  >
    <t:document>
    <t:documentHead>
    ...
    </t:documentHead>
<%

MyHandler myHandler = (MyHandler)FacesContext.getCurrentInstance().getApplication ().
getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(),"myHandler");
boolean validationFailed = myHandler.isValidationFailed();
%>
<f:verbatim>
<body onload="if(window.opener.fromPopup)updateParentWindow(<%= validationFailed %>); window.opener.fromLink = false;">

</f:verbatim>

    Some content
    ....

    ....

   <h:commandLink onclick="window.opener.fromPopup = true;" action="#{myHandler.myAction}">
    <h:outputText value="myAction"></h:outputText>
   </h:commandLink>  

<f:verbatim>
</body>
</f:verbatim>

</t:document>
</f:view>

oamSetHiddenInput is not defined – temporarily solution

If you use myfaces-1.1.5, you might have seen this error in you console. There are not too many sites presenting information about what’s causing this, and I struggled a bit myself trying to find out why my javascript console was flooded with this error message for each submit I did.

The problem appears if you have the org.apache.myfaces.AUTO_SCROLL parameter set to true, and you submit a form with one commandButton only. There is a JIRA-issue on it here, if you want some more specific information: MYFACES-1504. To give an example, this page would produce an error if AUTO_SCROLL is enabled:


<h:form id="myForm">

<t:commandButton id="submitMyFormButton"

value="Submit" action="#{myHandler.myAction}" ></t:commandButton >

</h:form>

There are no fixes to this problem yet (as of 20.01.2008), so until there is a version where this is corrected, simply add a hidden commandLink to the same form, and the problem goes away. You can’t hide it with the rendered attribute if myfaces, but have to hide it with css and styling:

<h:form id="myForm">
			<t:commandButton id="submitMyFormButton"
			value="Submit" action="#{myHandler.myAction}" ></t:commandButton >
			<t:commandLink id="stupidHiddenButtonToAvoidException"
			value="Nothing" style="display: none; visibility: hidden;"></t:commandLink>
</h:form>

Customize Tomahawk scheduler to support grouped entries and lazy loading

I am using myfaces (1.1.5) in my web application, and I was in the need of having some sort of a calendar/scheduler where the user would be able to add multiple records from one category/group/datatype. Imagine that you have multiple collections of some types of data, and each item within each type have date properties that could be presented in a calendar. I checked the scheduler of the Tomahawk library (1.1.6), but this was not supported by default. You could only add “standalone” entries, with no possibility of grouping them together.

Still, I decided to give it a try, and wanted to extend the scheduler to support this functionality. Another thought I had was that I wanted to only retreive the data I needed from the server, in other words: If a datatype have several thousand items, but in the month I’m currently viewing there are really just 18 representations, I would like to only fetch those 18 instances, not the whole collection every time.

In the following example I’ve only done the customization for the “month” mode, as this was the one of importance to me. But it should not be difficult to do this also for the other modes if that is needed.

To start, I decided to create a new class called SchedulerEntryGroup. Basically you can think of this as a group that holds from n to many items that should be entries in our calendar.


public class SchedulerEntryGroup
{
    private String name;
    private String dataTypeName;
    private List<Item> items;
    private String color;
    private boolean visible;
    private String dateProperty;
    private String displayProperty;

   public SchedulerEntryGroup()
    {
        items = new ArrayList<Items>();
    }

    publc SchedulerEntryGroup(String name, String color, boolean visible, String dataTypeName, String dateProperty,String displayProperty)
    {
        setName(name);
        setColor(color);
        setVisible(visible);
        setDateProperty(dateProperty);
        setDisplayProperty(displayProperty);
        setDataTypeName(dataTypeName);

    }

   .........
   SET/GET METHODS
   ......... 

}

As you can see the group holds properties like name (label), dataTypeName (which object-type it contains), the list of items and if it should be visible or not (to enable the possibility of activating/deactivating the displayed entries of a group with a checkbox e.g). It also contains a color property, as this should be common for all the entries of the same group. The dateProperty says which property that contains the dates, and the displayProperty which property should be displayed for the entry in the calendar.In my world the Item object holds a map with objects, and that’s why I pass properties as Strings to get them from the object. It’s basically the key in the properties-map. For reference a “short-version” of my Item-class looks like this:


public class Item
{
    private Map<String,Object> properties;

    public Item()
    {
        properties = new HashMap<String,Object>();
    }

    public Object getProperty(String key)
    {
        return properties.get(key);
    }

}

Ok, I have my entry-group now, but I also made a small change to the Entry class itself, as I wanted to have a color property. I extended the DefaultScheduleEntry and created a class SchedulerEntryExtended, the only difference adding a property color:


public class SchedulerEntryExtended extends DefaultScheduleEntry
{
    private String color;

    public SchedulerEntryExtended()
    {
        super();
    }

    public SchedulerEntryExtended(String description, boolean allDay, Date startTime, Date endTime, String title, String subTitle, String color)
    {
        super();
        super.setDescription(description);
        super.setAllDay(allDay);
        super.setStartTime(startTime);
        super.setEndTime(endTime);
        super.setTitle(title);
        super.setSubtitle(subTitle);
        setColor(color);
    }

    public String getColor()
    {
        return color;
    }
    public void setColor(String color)
    {
        this.color = color;
    }
}

Then I had to change the rendering of entries in month-mode, as I want the group’s color to be set as background-color for each entry. To do this I extended and overrode the DefaultScheduleEntryRenderer and created the class ScheduleEntryRenderer. There are two methods I override, the getColor and the renderCompactContent. The getColor was originally implemented like this:


public String getColor(FacesContext context, HtmlSchedule schedule,
                           ScheduleEntry entry, boolean selected)
    {
        return null;
    }

And the renderCompactContent was implemented like this:


protected void renderCompactContent(FacesContext context, ResponseWriter writer, HtmlSchedule schedule, ScheduleDay day, ScheduleEntry entry, boolean selected) throws IOException
    {
        StringBuffer text = new StringBuffer();
        Date startTime = entry.getStartTime();

        if (day.getDayStart().after(entry.getStartTime()))
        {
            startTime = day.getDayStart();
        }

        Date endTime = entry.getEndTime();

        if (day.getDayEnd().before(entry.getEndTime()))
        {
            endTime = day.getDayEnd();
        }

        if (!entry.isAllDay())
        {
            DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
            text.append(format.format(startTime));
            if (!startTime.equals(endTime)) {
                text.append("-");
                text.append(format.format(endTime));
            }
            text.append(": ");
        }
        text.append(entry.getTitle());

        writer.writeText(text.toString(), null);
    }

My ScheduleEntryRenderer class came out like this:

public class SchedulerEntryRenderer extends DefaultScheduleEntryRenderer
{
     public String getColor(FacesContext context, HtmlSchedule schedule,
             ScheduleEntry entry, boolean selected)
     {

	        SchedulerEntryExtended ent = (SchedulerEntryExtended) entry;
         return ent.getColor();
     }

	    protected void renderCompactContent(FacesContext context, ResponseWriter writer, HtmlSchedule schedule, ScheduleDay day, ScheduleEntry entry, boolean selected) throws IOException
     {

	        StringBuffer text = new StringBuffer();
         Date startTime = entry.getStartTime();

	        if (day.getDayStart().after(entry.getStartTime()))
         {
             startTime = day.getDayStart();
         }

	        Date endTime = entry.getEndTime();

	        if (day.getDayEnd().before(entry.getEndTime()))
         {
             endTime = day.getDayEnd();
         }

	        if (!entry.isAllDay())
         {
         	DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
         	text.append(format.format(startTime));
         	if (!startTime.equals(endTime)) {
         		text.append("-");
         		text.append(format.format(endTime));
         	}
         	text.append(": ");
         }
         text.append(entry.getTitle());

	        StringBuffer entryStyle = new StringBuffer();
 		  entryStyle.append("height: 100%; width: 100%;");
 		  String entryColor = getColor(context, schedule, entry, selected);
 		  if (entryColor != null)
 		  {
 		      entryStyle.append("border-color: ");
 		      entryStyle.append(entryColor);
 		      entryStyle.append(";");
 		      entryStyle.append("background-color: ");
 		      entryStyle.append(entryColor);
 		      entryStyle.append(";");
 		  }
 		  writer.startElement(HTML.DIV_ELEM, null);
 		  writer.writeAttribute(HTML.STYLE_ATTR,entryStyle.toString(), null);
 		  writer.writeText(text.toString(), null);
 		  writer.endElement(HTML.DIV_ELEM);
 	}
}

Notice that in getColor() I cast and use my SchedulerEntryExtended to retrieve the color. What I do in the renderCompactContent method is that I create an entryStyle string, and you can see that I apply the entryColor both to the border and the background. Then I wrap the text inside a div, and apply the entryStyle on this div. Thanks for examples at IRIAN and the tomahawk-examples.zip to point me in the direction of how to do this.

Then the main thing that remains is to have a handler that holds the model for the calendar, as well as having business-logic for using our entry-groups.This is my ScheduleHandler, which have methods for adding, deleting, displaying and hiding groups, as well as the method that creates the model of the calendar, createModel(). The “container” for all the groups that is to be rendered is a linked hashmap named schedulerMap:


public class SchedulerHandler implements Serializable
{
    private static final long serialVersionUID = -8815771399735333108L;

    private ScheduleModel model;
    private Map<String, SchedulerEntryGroup> schedulerMap;
    private SchedulerEntryGroup entryGroupToDelete;
    private SchedulerEntryGroup entryGroupToHide;
    private SchedulerEntryGroup entryGroupToDisplay;
    private Date selectedDate;

    public SchedulerHandler()
    {
        model = new SimpleScheduleModel();
        model.setMode(3);
        model.setSelectedDate(new Date());
        schedulerMap = new LinkedHashMap<String, SchedulerEntryGroup>();
        selectedDate = new Date();
        createModel();
    }

    public Collection<SchedulerEntryGroup> getEntryGroups()
    {
        return schedulerMap.values();
    }

    public void addGroup(SchedulerEntryGroup entryGroup)
    {
        schedulerMap.put(entryGroup.getName(), entryGroup);
        createModel();
    }

    public void hideEntryGroup()
    {
           SchedulerEntryGroup group = schedulerMap.get(getEntryGroupToHide().getName());
        group.setVisible(false);
        schedulerMap.put(group.getName(), group);
        createModel();
    }

    public void displayEntryGroup()
    {
        SchedulerEntryGroup group = schedulerMap.get(getEntryGroupToDisplay().getName());
        group.setVisible(true);
        schedulerMap.put(group.getName(), group);
        createModel();
    }

    public void deleteEntryGroup()
    {
        if(schedulerMap.containsValue(getEntryGroupToDelete()))
        {
            schedulerMap.remove(entryGroupToDelete.getName());
            createModel();
        }
    }

    public ScheduleModel getModel()
    {
        return model;
    }

    public void setModel(ScheduleModel model)
    {
        this.model = model;
    }

   private void createModel()
    {

        setModel(new SimpleScheduleModel());

        int i = 0;
        String id = "";
        for(Entry<String, SchedulerEntryGroup> e : schedulerMap.entrySet())
        {
            id = "Entry_"+e.getValue().getName()+i;
            SchedulerEntryGroup entryGroup = e.getValue();
            if(entryGroup.isVisible())
            {

                List<Item> items = entryGroup.getItems();

                for(Item i : items)
                {
                    SchedulerEntryExtended entry = new SchedulerEntryExtended();
                    entry.setColor(entryGroup.getColor());

                     Object o = i.getProperty(entryGroup.getDateProperty());

                     String s = (String) o;
                     Date d = null;
                     if(StringUtils.isNotBlank(s))
                     {
                        try
                        {
                            d = DateUtil.parseDate((String)o);
                        } catch (ParseException pe)
                        {
                            // TODO Auto-generated catch block
                            pe.printStackTrace();
                        }
                        model.setSelectedDate(d);
                        entry.setId(id);
                        entry.setTitle(i.getProperty(entryGroup.getDisplayProperty()));

                        entry.setStartTime(d);
                        entry.setEndTime(d);
                        entry.setAllDay(true);
                        model.addEntry(entry);
                     }
                     i++;
                }
           }
        }

        if(getSelectedDate() != null)
            model.setSelectedDate(getSelectedDate());
        else
            model.setSelectedDate(new Date());
        model.setMode(3);
        model.refresh();
    }

      public SchedulerEntryGroup getEntryGroupToDelete()
    {
        return entryGroupToDelete;
    }
    public void setEntryGroupToDelete(SchedulerEntryGroup entryGroupToDelete)
    {
        this.entryGroupToDelete = entryGroupToDelete;
    }
    public Date getSelectedDate()
    {
        return selectedDate;
    }
    public void setSelectedDate(Date selectedDate)
    {
        if(selectedDate != null)
        {
            this.selectedDate = selectedDate;
            getModel().setSelectedDate(selectedDate);
            createModel();
        }
    }
    public SchedulerEntryGroup getEntryGroupToHide()
    {
        return entryGroupToHide;
    }
    public void setEntryGroupToHide(SchedulerEntryGroup entryGroupToHide)
    {
        this.entryGroupToHide = entryGroupToHide;
    }
    public SchedulerEntryGroup getEntryGroupToDisplay()
    {
        return entryGroupToDisplay;
    }
    public void setEntryGroupToDisplay(SchedulerEntryGroup entryGroupToDisplay)
    {
        this.entryGroupToDisplay = entryGroupToDisplay;
    }

}

To add a group just create a new instance of it, fill up and set the Item-collection, and pass the group as an argument to the addGroup()-method like this:


public void addEntryGroup()
{
        boolean visible = true;
        SchedulerEntryGroup entryGroup = new SchedulerEntryGroup("myGroup","#CCDD00",visible, "THE_TYPE_OF_DATA", "THE_DATE_PROPERTY", "THE_DISPLAY_PROPERTY");
        SomeService service = new SomeService();
        entryGroup.setItems(someService.getItems("THE_TYPE_OF_DATA", "THE_DATE_PROPERTY"));
        getSchedulerHandler().addGroup(entryGroup);
}

And as you can see the createModel()-method loops the map, and if the group is visible it adds all the items of this group as entries to the calendar. I call createModel() whenever a group is updated or added/deleted, as well as if the selected date of the calendar changes. The “setEntryGroupToDisplay/Hide/Delete()”-methods are used from a jsp/menu to be able to manage the content of the calendar. To hide a group e.g. you could do it very easily with a commandLink and an updateActionListener:


<h:commandLink id="hideLink"  styleClass="myLink" rendered="#{entryGroup.visible}" action="#{schedulerHandler.hideEntryGroup}"  >
          <t:graphicImage value="/images/checkBoxChecked.gif" border="0"></t:graphicImage>
          <t:updateActionListener  value="#{entryGroup}"  property="#{schedulerHandler.entryGroupToHide}"></t:updateActionListener>
</h:commandLink>

Following this example you should now be able to use your calendar with grouped entries. Nice!

But in the beginning of this post I said that I didn’t want to retrieve more items from my backend than I needed to. As the code is now, all the items in the list of the entryGroup are added to the model, and the entryGroup is created before it is aware of which date the calender is currently displaying. This means that it’s impossible to know which items to retreive, as you don’t know which ones are needed.To give the entryGroup knowledge of this, I added a property called dateToFetchFrom, and I move the responsibility of filling up the items-list inside the group-object itself. This is solved by the “fetchItems()”-method. In the calendar-view, if you display a month, it might also contain some days of the previous month as well as the next month. Because of that the date-range I decided to retrieve items for is those three months, the current month, and that month -1 and that month + 1. My SchedulerEntryGroup then became like this:


public class SchedulerEntryGroup
{
    private String name;
    private String dataTypeName;
    private List<Item> items;
    private String color;
    private boolean visible;
    private String dateProperty;
    private String displayProperty;
    private Date dateToFetchFrom;

   public SchedulerEntryGroup()
    {
        dateToFetchFrom = new Date();
	items = new ArrayList<Items>();
    }

    publc SchedulerEntryGroup(String name, String color, boolean visible, String dataTypeName, String dateProperty,String displayProperty)
    {
        setName(name);
        setColor(color);
        setVisible(visible);
        setDateProperty(dateProperty);
        setDisplayProperty(displayProperty);
        setDataTypeName(dataTypeName);

    }

    public void fetchItems()
	{
		Calendar cal = new GregorianCalendar();
		cal.setTime(getDateToFetchFrom());

		cal.add(Calendar.MONTH, -1);
		Date fetchFrom = cal.getTime();
		cal.add(Calendar.MONTH, +1);
		Date fetchTo = cal.getTime();

		List<Item> itemsFetched = new ArrayList<Item>();
		SomeBackendService service = new SomeBackendService();
		service.getItems(getDataTypeName(), getDateProperty(), getDisplayProperty(), fetchFrom, fetchTo );
		setItems(itemsFetched);
	}
   .........
   SET/GET METHODS
   ......... 

}

Of course we then need to modify the createModel() of the SchedulerHandler as well, as we need to take use of the new dateToFetchFrom property as well as the fetchItems()-method. The modified version of createModel() is like this:

private void createModel()
    {
    	setModel(new SimpleScheduleModel());
    	int i = 0;
    	String id = "";
    	for(Entry<String, SchedulerEntryGroup> e : schedulerMap.entrySet())
    	{
    		id = "Entry_"+e.getValue().getName()+i;

    		SchedulerEntryGroup entryGroup = e.getValue();
    		if(entryGroup.isVisible())
    		{

    			entryGroup.setDateToFetchFrom(getSelectedDate());
    			entryGroup.fetchItems();

			List<Item> items = entryGroup.getItems();

                for(Item i : items)
                {
                    SchedulerEntryExtended entry = new SchedulerEntryExtended();
                    entry.setColor(entryGroup.getColor());

                     Object o = i.getProperty(entryGroup.getDateProperty());

                     String s = (String) o;
                     Date d = null;
                     if(StringUtils.isNotBlank(s))
                     {
                        try
                        {
                            d = DateUtil.parseDate((String)o);
                        } catch (ParseException pe)
                        {
                            // TODO Auto-generated catch block
                            pe.printStackTrace();
                        }
                        model.setSelectedDate(d);
                        entry.setId(id);
                        entry.setTitle(i.getProperty(entryGroup.getDisplayProperty()));

                        entry.setStartTime(d);
                        entry.setEndTime(d);
                        entry.setAllDay(true);
                        model.addEntry(entry);
                     }
                     i++;
                }
           }
        }

        if(getSelectedDate() != null)
            model.setSelectedDate(getSelectedDate());
        else
            model.setSelectedDate(new Date());
        model.setMode(3);
        model.refresh();
    }

We see that for each group that is visible, we set the selectedDate of the calendar, and we then execute the fetchItems()-method based on this. If somebody changes the date of the calendar, createModel() is called again, and a new date-range will be the criteria for retrieving items.

As a last comment on the scheduler, I can say that I was troubled by some css-styling and that the borders of the scheduler didn’t render correctly. In my web application I have a style-property on the table tag that says “border-collapse: collapse”. This also effected the rendering of the calendar in Firefox, there were no borders around each day, so the view looked a bit messy. For other reasons I could not remove or change the table tag, so I had to edit the stylesheet of the calendar myself. In the library this can be found under tomahawk-1.1.6.jar\org\apache\myfaces\custom\schedule\resource\css and is named schedule.css. I made the following change to apply separate borders for tables created inside the scheduler only (apply the style to all tables that are children of the div named schedule-compact-default):


div[class=schedule-compact-default]>table
{
border-collapse: separate !important;
}

Ok, I hope that this example have given you some tips on how you can customize the scheduler component. Good luck!

Lazy loading of tables in JSF – working with large amount of data

The challenge working with a large amount of data in user-presentation is to serve the user an easy and effective way of getting to the information he/she is looking for. If you have a table with 50.000 rows, you would in some way need to chop the information in smaller pieces, for example having multiple pages displaying 50 rows each, and then having a way of navigating through the pages.

But still, there are some considerations to do this in a way that opts for performance. If the user selects do display page 2, meaning rows 50-100, wouldn’t you like to fetch only those, not all the 50.000 rows? And like in JSF, if you have multiple components (dataTables, dataScrollers) that are dependent on/using the same data, you would like that the data is only retrieved once, not one time for each component. Doing web applications, being able to limit the amount of data that is fetched from the backend is a key to success when it comes to performance and operability issues.

My example is based on Cagatay Civiciโ€™s post http://cagataycivici.wordpress.com/2006/07/10/jsf_datatable_with_custom_paging/,
so I will not go through the technical solution and how the “lazy” data model works once more, I suggest you read his post for that. But I give a complete example of how to use his PagedListDataModel, and in addition how to make sure the data is retrieved only once by using phaseListeners.

To keep it simple, let’s imagine that we have a Dictionary in the backend, and a jsp page with static links with letters like ‘A’, ‘B’, ‘C’ and so on throughout the alphabet. Pressing on one of the letters would display all the words that starts with it in the dataTable, and we can use a dataScroller to navigate through multiple pages.

This is my jsp, in which I’ve removed the columns of the dataTable as they are of no importance. Note that the dataTable is set with a valueBinding, and that the value of it is pointing to a dataModel. Also note that we do not render the table if no one has selected a letter. I also just give one link as an example of how to update the property we can refer to as the “selected letter”:

<h:commandLink styleClass="myLink" value="A">
	<t:updateActionListener value="A" property="#{myDataModelHandler.selectedLetter}"></t:updateActionListener>
</h:commandLink>
<h:panelGrid id="mainPanel" width="100%">
	<t:dataTable
	  id="htmlTableView"
	  value="#{myDataModelHandler.activeDataModel}" rendered="#{myDataModelHandler.selectedLetter != null}"
	  binding="#{myHtmlDataTableHandler.htmlDataTable}"
	  headerClass="tableViewHeader"
	  var="row">
	</t:dataTable>
	<t:panelGrid id="footerPager">
		 <t:dataScroller id="ds5"
				for="htmlTableView"
				fastStep="5"
				styleClass="scroller"
				paginator="true"
				paginatorMaxPages="5"
				paginatorTableClass="paginator"
				paginatorActiveColumnStyle="font-weight:bold;"
				rowsCountVar="rowsCount"
				renderFacetsIfSinglePage="true"
			>
			<f:facet name="previous">
				<t:graphicImage id="datascrollerPrevious" value="/images/left-one-step.gif" border="1" styleClass="dataScrollerImage"/>
			</f:facet>
			<f:facet name="next">
				 <t:graphicImage id="datascrollerNext" value="/images/right-one-step.gif" border="1" styleClass="dataScrollerImage"/>
			</f:facet>
			<f:facet name="first">
				<t:graphicImage id="datascrollerFirst"
				value="/images/left.gif" border="1" styleClass="dataScrollerImage"/>
			</f:facet>
			<f:facet name="last">
				 <t:graphicImage id="datascrollerLast"
				 value="/images/right.gif" border="1" styleClass="dataScrollerImage" />
			</f:facet>
		 </t:dataScroller>
	 </t:panelGrid>
</h:panelGrid>

This is the handler (backing bean) that holds the htmlDataTable:

public class MyHtmlDataTableHandler
{
    private HtmlDataTable htmlDataTable;
    public MyHtmlDataTableHandler()
    {

    }

    public HtmlDataTable getHtmlDataTable()
    {
        if(htmlDataTable == null)
        {
            log.debug("htmlDataTable == null");
            HtmlDataTable dataTable = new HtmlDataTable();
            dataTable.setRows(50);
            setHtmlDataTable(dataTable);
        }
        return htmlDataTable;
    }

    public void setHtmlDataTable(HtmlDataTable htmlDataTable)
    {
            this.htmlDataTable = htmlDataTable;
    }
}

You can see that I have modified the getter to create a new instance if the instance it holds is null. It’s important to set the number of rows here, or it will fail when trying to build the lazy data model.The dataModel we use for our dataTable is created and set before the RENDER_RESPONSE phase, as mentioned earlier this is to avoid that the data itself is retrieved multiple times. To be able to do this we need to use a phaseListener, so we implement it in our constructor of the dataModelHandler. Note that we have references here to the dataTableHandler as well as a util for helping us creating a paged data model. As you can see in the phaseListener beforePhase()-method, if no letter has been selected, we don’t create or set the model.

public class MyDataModelHandler
{
	private String selectedLetter;
	private PagedListDataModel activeDataModel;

	private MyHtmlDataTableHandler myHtmlDataTableHandler; //BEAN_REFERENCE SET IN FACES-CONFIG
	private PagedDataModelUtil pagedDataModelUtil; //BEAN_REFERENCE SET IN FACES-CONFIG

	public MyDataModelHandler()
	{
		LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
		Lifecycle lifecycle = lifecycleFactory.getLifecycle(lifecycleFactory.DEFAULT_LIFECYCLE);

		lifecycle.addPhaseListener
		(
			new PhaseListener()
			{
				public void afterPhase(PhaseEvent arg0)
				{
				}
				public void beforePhase(PhaseEvent arg0)
				{
					if(selectedLetter != null)
					{
						setActiveDataModel(pagedDataModelUtil.createPagedDataModel(selectedLetter, getMyHtmlDataTableHandler().getHtmlDataTable()));
					}
				}	

				public PhaseId getPhaseId()
				{
					return PhaseId.RENDER_RESPONSE;
				}
			}
		);
	}

	public String getSelectedLetter()
	{
		return selectedLetter;
	}

	public void setSelectedLetter(String selectedLetter)
	{
		this.selectedLetter = selectedLetter;
	}

	public PagedListDataModel getActiveDataModel()
	{
		return activeDataModel;
	}

	public void setActiveDataModel(PagedListDataModel activeDataModel)
	{
		this.activeDataModel = activeDataModel;
	}

	public MyHtmlDataTableHandler getMyHtmlDataTableHandler()
	{
		return myHtmlDataTableHandler;
	}

	public void setMyHtmlDataTableHandler(MyHtmlDataTableHandler myHtmlDataTableHandler)
	{
		this.myHtmlDataTableHandler = myHtmlDataTableHandler;
	}

	public PagedDataModelUtil getPagedDataModelUtil()
	{
		return pagedDataModelUtil;
	}

	public void setPagedDataModelUtil(PagedDataModelUtil pagedDataModelUtil)
	{
		this.pagedDataModelUtil = pagedDataModelUtil;
	}
}

The pagedDataModel we create is an instance of PagedListDataModel which is exactly the same as in Cagatay Civici’s post:

public class PagedListDataModel extends DataModel
{
  private int rowIndex = -1;
  private int totalNumRows;
  private int pageSize;
  private List list;

  public PagedListDataModel(List list, int totalNumRows, int pageSize)
  {
    setWrappedData(list);
    this.totalNumRows = totalNumRows;
    this.pageSize = pageSize;
  }

  public boolean isRowAvailable()
  {
    if(list == null)
      return false;
    int rowIndex = getRowIndex();
    if(rowIndex >=0 && rowIndex < list.size())
      return true;
    else
      return false;
  }

  public int getRowCount()
  {
    return totalNumRows;
  }

  public Object getRowData()
  {
    if(list == null)
      return null;
    else if(!isRowAvailable())
      throw new IllegalArgumentException();
    else
	{
      int dataIndex = getRowIndex();
      return list.get(dataIndex);
    }
  }

  public int getRowIndex()
  {
    return (rowIndex % pageSize);
  }

  public void setRowIndex(int rowIndex)
  {
    this.rowIndex = rowIndex;
  }

  public Object getWrappedData()
  {
    return list;
  }

  public void setWrappedData(Object list)
  {
    this.list = (List) list;
  }

}

&#91;/sourcecode&#93;
As you see from the beforePhase()-method in the phaseListener I use a util to create the pagedDataModel. In my application I have a index on the back, but this can of course differ from your situation. I will therefore refer to the backend as "service", and whatever you use that holds and gets the data should not matter.
&#91;sourcecode language='java'&#93;
public class PagedDataModelUtil
{
	public PagedListDataModel createPagedDataModel(String selectedLetter, HtmlDataTable htmlDataTable)
	{
			int startPosition = htmlDataTable.getFirst();
			int dimensionToUse = htmlDataTable.getRows();
			Service service = new Service();
			int totalListSize = service.getTotalNumberOfHits(selectedLetter);

			List<Word> words = new ArrayList<Word>();
			words.addAll(service.getHits(selectedLetter, startPosition, dimensionToUse ));
			PagedListDataModel dataModel = new PagedListDataModel(words, totalListSize, dimensionToUse);
			return dataModel;
	}
}

So, we have now a table that retrieves only the data the user wants to see, and the data is not retrieved multiple times. Fine!But then, what about sorting?? Let’s say that one of the columns we have in our table is length, meaning the length of the word in number of characters. What if I want to sort by this?You could do this as well. I assume you have a header in your table, giving the labels for each column. You can create a commandLink on each label, and if you press one of them you set that value into a property, for example “sortedBy” in the dataModelHandler.First, the link:

 			<t:column>
				<f:facet name="header">
					<t:commandLink id="sortBySomethingLink" value="myColumnLink">
						<t:updateActionListener property="#{myDataModelHandler.sortedBy}" value="theFieldNameIWantToSortOn"></t:updateActionListener>

					</t:commandLink>
				</f:facet>
				<h:outputText value="#{someObject.someValue}" />

			</t:column>

We see that this link updates the property sortedBy in the MyDataModelHandler with the value specified. In the phaseListener, when we call the createPagedDataModel, we now need to pass this property.In other words we modify the createPagedDataModel() method to add support for sorting. We have a new parameter called sortedBy, and use StringUtils to test whether we should bring this one into play or not. If it is null or “” (blank), we don’t sort. We could also keep the sortedBy parameter as a property in our PagedDataModelUtil, in this way we can have an ascending / descending functionality. If the sortedBy parameters equals the sortedBy property, we flip the ascending boolean, if not we sort ascending by default:


private String sortedByLast = "";
private boolean ascending = true;

public PagedListDataModel createPagedDataModel(String selectedLetter, HtmlDataTable htmlDataTable, String sortedBy)
{
			int startPosition = htmlDataTable.getFirst();
			int dimensionToUse = htmlDataTable.getRows();
			int totalListSize = service.getTotalNumberOfHits(selectedLetter);

			List<Word> words = new ArrayList<Word>();
			if(StringUtils.isNotBlank(sortedBy))
			{
				if(sortedBy.equalsIgnoreCase(sortedByLast))
					ascending = !ascending;
				else
					ascending = true;

				words.addAll(service.getHitsSorted(selectedLetter, startPosition, dimensionToUse, sortedBy, ascending));
			}
			else
				words.addAll(service.getHits(selectedLetter, startPosition, dimensionToUse ));

			PagedListDataModel dataModel = new PagedListDataModel(words, totalListSize, dimensionToUse);
			return dataModel;
}

Of course, this puts the responsibility of sorting on the backend service. Somewhere we need to do the sorting. ๐Ÿ™‚ If you use a database and have a high number of rows/items, this might be a performance issue. In my application I use Lucene (index), and even with a very high number of rows I don’t have any problems with performance. But doing the sorting in the backend and getting the first 25 items e.g. is anyway faster than retrieving all the items and then do sorting.Ok, that was all this time!

How to do proper URL Encoding in Javascript when using window.open()

In some cases you might want to do encoding of URL-parameters directly inside javascript, simply because you think it’s best to do it there or because you have no other options of getting the parameters encoded. But as I discovered when trying to do this myself, doing this in javascript is not like a walk in the park, or at least there are some important “black holes” you should be aware of.

In my example I use JSF, and I have a h:dataTable component which I build up programmatically in java. For each row I have a link that will open a new popup window that points to another page (jsp) passing some parameters. I needed to do javascript-encoding of parameters, because when I build my table I use expression language (EL – #{} ) and valueBindings (for those of you that are familiar with it). If you use expressions you don’t hold the value itself, but the expression will be “decoded” run-time when the page is rendered.

To show an example, I have a Java-class that has a hashmap called properties, an ordinary key-value thing. By using a get-method that returns the whole map it’s possible through EL to give an “input-parameter” on which property to get. My get-method:

public Map<String, Object> getProperties()
{
	return properties;
}

this would be the expression to get the url:

String url = "#{row.properties['"+SOME_KEY_THAT_POINTS_TO_OBJECT_WITH_URL+"']}";

And then I would create my link in java with value-binding like this:

HtmlOutputLink htmlOutputLink = new HtmlOutputLink();
ValueBinding vb = FacesContext.getCurrentInstance().getApplication().createValueBinding(
"popupWindow('"+ url +"','MY_POPUP_WINDOW', WIDTH,HEIGHT); return false;");
htmlOutputLink.setValueBinding("onclick",vb);

The “normal” way of doing encoding java-side would be something like this:

public String urlEncode(String urlToEncode)
{
	String encodedUrl = "";
	if(urlToEncode != null)
	{
		try
		{
 			encodedUrl = URLEncoder.encode(urlToEncode,"UTF-8");
		}
		catch (Exception e)
 		{
			log.error("Encode exception when encoding url: " + urlToEncode,e);
 			return urlToEncode; //Return unencodedUrl
		}

		return encodedUrl;
	}
}

But in my case, if I were to encode the url before passing it to the javascript, what I would encode would actually be my expression, not the value of it. The result of this encoding would be something like;

 %23%7Brow.properties%5B%27SOME_KEY_THAT_POINTS_TO_OBJECT_WITH_URL%27%5D%7D.

Thus, I was in the need of doing the encoding after the page has been rendered, and then I needed to do it inside the javascript.

I tried two different approaches for encoding the url, the first one which I expected would work, and the second one which I had to do to make it work. What you need to be aware of is that default encoding in javascript is the UTF-8 format, so if you try to decode “on the other side” you have to use UTF-8 in your decoder. I’ve also seen some examples around saying that the escape()-function does some sort of encoding, but this one just escapes (replaces) special characters, for example it converts white-spaces to %20%. Trying to use escape() on the URL and then decoding it with an URL-decoder would fail! Still, I found the need of using the escape()-function as well, and will explain this as I go.

The first function I tried uses the encodeURI()-function inside javascript directly:

function encodeUrl(url)
{
	return encodeURI(url);
}

And from my popupWindow()-function I call the encodeUrl() like this:

var newWindow = '';
function popupWindow(url, name, width, height)
{
	name = name.replace(/\/|\-|\./gi, "");
	var whitespace = new RegExp("\\s","g");
	name = name.replace(whitespace,"");
	if (!newWindow.closed && newWindow.location)
	{
		newWindow.location.href = encodeUrl(url);
	}
	else
	{
		newWindow = window.open(encodeUrl(url),name, "location=no, scrollbars=yes, resizable=yes, toolbar=no, menubar=no, width=" + width + ", height=" + height );
		if (!newWindow.opener)
			newWindow.opener = self;
	}
	if (window.focus)
	{
		newWindow.focus()
	}
}

But doing it like this the decoding seemed to fail, as I couldn’t get the proper value from the url on the receiving side (decodedValue != encodedValue). Having struggled with this one for some time, I discovered that the window.open()-function actually tries to do some sort of decoding of the url itself before it passes it on. So I created another method that encodes on parameter level, and which also uses the escape-method to “protect” the encoded parameters from the window.open()-function.

function encodeUrl(url)
{
 	if (url.indexOf("?")>0)
 	{
		encodedParams = "?";
 		parts = url.split("?");
 		params = parts[1].split("&");
 		for(i = 0; i < params.length; i++)
 		{
			if (i > 0)
	 		{
				encodedParams += "&";
			}
			if (params[i].indexOf("=")>0) //Avoid null values
			{
				p = params[i].split("=");
				encodedParams += (p[0] + "=" + escape(encodeURI(p[1])));
			}
			else
			{
				encodedParams += params[i];
			}
		}
		url = parts[0] + encodedParams;
	}
	return url;
}

One thing to mention in this function is that is uses the encodeURI()-function. This one doesn’t do anything with the reserved characters like ; , / ? : @ & = + $. If you for some reason need to encode these as well, you should use the encodeURIComponent()-function.I tried to do this function without the use of escape(), but then the parameters “arrived” wrongly encoded, and became “corrupted” after I decoded them. Wrapping the encodeURI() inside an escape() solved this problem:

encodedParams += (p[0] + "=" + escape(encodeURI(p[1])));

Finally, inside my receiving page, I managed to decode the parameters and get the values I actually submitted with a java decoding method like this:

public String urlDecode(String urlToDecode)
{
	String decodedUrl = "";
 	if(urlToDecode != null)
 	{
 		try
 		{
 			decodedUrl = URLDecoder.decode(urlToDecode,"UTF-8");
 		}
 		catch (Exception e)
 		{
 			log.error("INVALID URL: " + urlToDecode,e);
 			return "";
 		}
 	}
	return decodedUrl;
}

This way of doing it also works for special characters belonging to the ISO-8859-1 encoding, even if the encoding used is actually UTF-8. As a small reference I can list the proper UTF-8 encoding for the Scandinavian specific characters if you use those, in this way you should be able to check whether your URL is encoded correctly or not if you print it out before decoding it.

  • รฆ = %E6
  • รธ = %F8
  • รฅ = %E5
  • ร† = %C6
  • ร˜ = %D8
  • ร… = %C5

You can also check out this page for a complete reference of encoded characters: http://www.w3schools.com/tags/ref_urlencode.asp

If you want to try an example of how encodeURI and encodeURIComponent works, copy and paste the following javascript and test with your own strings:


<script type="text/javascript">

                var unencodedText = "This is my text that contains whitespaces and characters like # and ร˜";
                var encodedText = "";
                var decodedText = "";
                alert('unencodedText: ' + unencodedText);

                //To encode whitespaces and the 'ร˜' character - use encodeURI
                encodedText = encodeURI(unencodedText);
                //We see that whitespaces and 'ร˜' are encoded, but the '#' is still there:
                alert('encodedText: ' + encodedText);

                //If we decode it we should get our unencodedText back
                decodedText = decodeURI(encodedText);
                alert('decodedText: ' + decodedText);

                //To also encode the '#' we use the encodeURIComponent
                encodedText = encodeURIComponent(unencodedText);
                //Now all the characters have been encoded:
                alert('encodedText: ' + encodedText);

                //To get our unencodedText back we now need to use the decodeURIComponent
                decodedText = decodeURIComponent(encodedText);
                alert('decodedText: ' + decodedText);

            </script>

I hope that you might find this post useful, and that it might save you from some pain in the a** if you try to use the encoding capabilities of Javascript.

Using JSON with JSF

This post will describe what to do if you want to use JSON in your web applications together with JSF. JSON (JavaScript Object Notation) is a way of doing information interchange between your programming language and javascript. In other words you can use it to access for example java objects in the world of javascript, and this will give you the possibility of creating more advanced web applications. Some basic knowledge of javascript is recommended.

  1. First thing to do is to download the JSON RPC library from JsonRpc and put it in your WEB-INF/lib directory (or the directory you use that holds the libs and is packaged together with the war-file). Also remember to add the library to the classpath of your project in Eclipse or other software frameworks you use to develop.
  2. Then secondly you need to include the jsonrpc.js javascript in the header of your page. The script can be found within the downloaded lib inside \json-rpc-java-1.0.1\webapps\jsonrpc. You include it by writing something similar like this in your header:
    <script type="text/javascript" src="${pageContext.request.contextPath}/javascript/jsonrpc.js"></script>
  3. Then you need to add the servlet configuration to the web.xml
    <servlet>
    
    	<servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>
    
    	<servlet-class>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-class>
    
    </servlet>
    
    <servlet-mapping>
    
    	<servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>
    
    	<url-pattern>/JSON-RPC</url-pattern>
    
    </servlet-mapping>
  4. Then, on top of your page (outside the <f:view> tags) you write:
    <jsp:useBean id="JSONRPCBridge" scope="session"class="com.metaparadigm.jsonrpc.JSONRPCBridge" />
  5. Then you must register the handler/backing bean you want the json to access. Do this inside the <f:view> tags but within jsp code tags
    </pre>
    <pre><%
    
    MyHandler myHandler = (MyHandler )FacesContext.getCurrentInstance().getApplication ()
    
    .getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(),"myHandler ");
    
    JSONRPCBridge.registerObject("myHandler ", myHandler );%>
  6. From javascript side, you can now access you handler, set properties and execute methods like this:
    function JsonTest()
    
    {
    
    	try
    
    	{
    
    		//The input-parameter to the JSONRpcClient is basically the path to
    		//the servlet you registered in web.xml
    
    		jsonrpc = new JSONRpcClient("/YOUR_APPLICATION_CONTEXT_ROOT/JSON-RPC");
    
    		// Call a Java method
    
    		var result = jsonrpc.myHandler.getTestValue();
    
    		//Do something with result.....
    
    		jsonrpc.myHandler.setTestData("SET A PROPERTY TO SOMETHING");
    
    		jsonrpc.myHandler.execute(); //Execute a method
    	}
    
    	catch(e)
    
    	{
    
    		alert(e);
    
    	}
    
    }

Good luck!