wiki:Devel/Index

UTGB Request Dispatcher Mechanism

source:trunk/utgb/utgb-core/src/main/java/org/utgenome/gwt/utgb/server/RequestDispatcher.java

web.xml setting

Add the following description into your web.xml:

  <filter>
    <filter-name>RequestDispatcher</filter-name>
    <filter-class>org.utgenome.gwt.utgb.server.RequestDispatcher</filter-class>
    <!-- set the param-value element value to true when running your application in GWT's hosted-mode. --> 
    <init-param>
      <param-name>gwt-hosted-mode</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>
  
  <!-- This setting maps all HTTP requests to the RequestDispatcher filter servlet. -->
  <filter-mapping>
    <filter-name>RequestDispatcher</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

config/track-config.xml

<config version="1.0">
  <import actionPackage="org.utgenome.gwt.utgb.server.app"/>
</config>

* The lines, param-name=base-package, param-value=(application base) specify the location (base package name) where the RequestDispatcher? recursively searches for RequestHandler? implementations (Java classes). * With the above setting, an HTTP request, e.g., http://localhost:8989/hello, is mapped to the request handler org.utgenome.gwt.utgb.server.app.Hello class.

The upper letters are converted into the lower letters when mapping the request, e.g., Hello action can be accecced via hello.action URL. * Another example using hierarchies of actions: http://localhost:8989/admin/login.action is mapped to org.utgenome.gwt.utgb.server.app.admin.Login class.

Automatic Data Binding to Request Handler

Your RequestHandler? implemnatation (say Hello.java) can have serveral parameter values, e.g., name and year:

public class Hello implements RequestHandler
{
  private String name = "";
  private int year = 2000;

  public void handle(HttpServletRequest request, HttpServletResponse response)
  {
      PrintWriter out = response.getWriter().println("Hello " + name + "(" + year + ")");
  }

  public void setName(String name) { this.name = name; }
  public void setYear(int year) { this.year = year; }
}


Our RequestDispatcher? automatically sets these parameter values from a given HTTP request. For example, an HTTP request

http://localhost:8989/hello.action?name=leo&year=2007

will invoke setName("leo") and setYear(2007) methods.

Note that, although the query string in the HTTP request consists of string values "leo" and "2007", our BeanUtil? library detects the data type to which the string should be translated by analysing the class definition. In this example, the string value

"2007" is translated into an integer, 2007.

The web page result of the avobe request looks like as this:

Hello leo(2007)

Using Dispatcher in GWT Hosted Mode

Unfortunately, GWT-hosted mode that uses gwt-embedded TomcatServer? and GWTShell, does not support servlet-mapping in web.xml, since every path (/*) is already mapped to GWTShellServlet, which redirects HTTP requests within GWT Shell to the public folder within the module directory or servlet codes within the server folder.

  • Reference: tomcat/webapps/ROOT/WEB-INF/web.xml (the web app configuration file used in GWT-hosted mode)
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
    
    	<servlet>
    		<servlet-name>shell</servlet-name>
    		<servlet-class>com.google.gwt.dev.shell.GWTShellServlet</servlet-class>
    	</servlet>
    	
    
      <servlet-mapping>
        <servlet-name>shell</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
      
    </web-app>
    
    

Anywary, GWTShellServlet is mandatory to debug client-side codes within within Eclipse (or other IDEs).

The problem is, there is no way to use the following web.xml setting effectively.

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>

Even if you put the avobe setting into tomcat/webaps/ROOT/WEB-INF/web.xml, it does not work because the mapping /* to GWTShellServlet overshadows other mappings.

In order to use RequestDispatcher?, which support rappid web application development, we introduce some tricks that change query arguments to the RequestDispather?.

First, you have to set a servlet path within your GWT module xml file. (*.gwt.xml):

<module>

	<!-- Inherit the core Web Toolkit stuff.                  -->
		<inherits name="org.utgenome.gwt.web.Web"/>
		<inherits name='com.google.gwt.user.User'/>
		<inherits name="com.google.gwt.json.JSON"/>
		<inherits name="com.google.gwt.http.HTTP"/>
		<inherits name="com.google.gwt.xml.XML"/>
	<!-- Specify the app entry point class.                   -->
	<entry-point class='org.utgenome.gwt.utgb.client.UTGBResourceCenter'/>
   
   <servlet path="/dispatcher" class="org.utgenome.gwt.utgb.server.RequestDispatcher"/>
   
</module>

This setting redirects a request for GWT.getModuleBaseURL() + "/dispatcher" to the RequestDispatcher? servlet. This setting works only in GWT-hosted mode.

And then, write a URL resolver method anywhere within client-side codes you want:

    public static String getActionURL(String actionName, String queryString)
    {
        if(GWT.isScript())
        {
            return GWT.getModuleBaseURL() + actionName + ".action?" + queryString;
        }
        else
        {
            return GWT.getModuleBaseURL() + "dispatcher?actionClass=" + "org.utgenome.gwt.utgb.server.app"
              + "." + actionName + "&" + queryString;
        }
    }

This method yields the appropriate URLs to access the RequestDispatcher? both in hosted-mode and web-mode. For example, getActionURL("hello", "name=leo") returns:

  • (GWT moduleBase)/hello.action?name=leo (in web-mode)
  • (GWT moduleBase)/dispatcher?actionClass=org.utgenome.gwt.utgb.server.app.hello&name=leo (in hosted-mode)

You must set the same value to the web.xml (for web-mode) and the string value (e.g., "org.utgenome.gwt.utgb.server.app.") in the getActionURL() mehtod.

The RequestDispatcher? gives priority to the actionClass parameter if it is contained in the HTTP request.