1 Getting started for users

In the following section it is assumed that you have knowledge how to build a normal Struts application and also a J2ME application. In addtion we assume that you have downloaded the binary distribution which contains the 3 jar files.

This document describes in general terms how to broaden your existing web application to support a mobile client. In the following we assume you have a existing Struts application called Yourapp .

The rest of the document will speak about the 3 modules.

Yourapp-Common
contains commonly used resources and classes. Those classes, which needs to be serialized for the communication between the client and the server, have to be implemented in one package. This package could be configured in the web.xml of the Yourapp-Server.
Yourapp-Server
Rename Yourappto Yourapp-Server. No special artifacts are needed here.
Yourapp-Client
implement your client-midlet here. The figure 1gives an overview of the needed artifacts of the client.


Abbildung 1: Directorystructure of the client

1.1 Setting up the modules

Yourapp-Server

Include the StrutsME-Server - and the Yourapp-Common-jarfile in the classpath of your server.

Integrating the StrutsMERequestProcessor

This could be done by one of the following options.

  • integration of the StrutsMERequestProcessor in the inheritancehierarchie of your own Requestprocessor.
  • Adding the following line to your struts-config.xml AND ALL module configurations:
     
     <controller 
            processorClass="org.strutsme.server.StrutsMERequestProcessor"/>
    
    


    Listing 1: Struts-config.xml

web.xml

In the web.xml under the servlet entry for the StrutsActionServlet insert:

 
 <init-param> 
       <param-name>packagePrefix</param-name> <param-value>foo.dto.</param-value> </init-param>



Listing 2: modified web.xml

Yourapp-Common and Yourapp-Client

  • copy the cldcapi*.jars and midp*.jars of the Wireless Toolkit into your maven-repository in the subdirectory strutsme/jars .
  • copy the StrutsME -jars into the same directory as above.
  • setup your project.xml and integrate the following listing.

     
    		<dependency>
     			<groupId>strutsme</groupId>
    			<artifactId>cldcapi</artifactId>
    			<version>${wtk.cldc.version}</version>
     			<jar>cldcapi${wtk.cldc.version.maven}.jar</jar>
    			<type>jar</type>
    		</dependency>
    		<dependency>
    			<groupId>strutsme</groupId>
    			<artifactId>midpapi</artifactId>
    			<version>${wtk.midp.version}</version>
    			<jar>midpapi${wtk.midp.version.maven}.jar</jar>
    			<type>jar</type>
    		</dependency>
            <dependency>
    			<groupId>strutsme</groupId>
    			<artifactId>strutsme-common</artifactId>
    			<version>SNAPSHOT</version>
    			<type>jar</type>
    		</dependency>
    		<dependency>
    			<groupId>strutsme</groupId>
    			<artifactId>strutsme-client</artifactId>
    			<version>SNAPSHOT</version>
    			<type>jar</type>
    		</dependency>
    
    


    Listing 3: project.xml

    For the Common-Module of your application in most cases you only need to include the strutsme-common-${version}.jar .
  • run maven clean . This will download the required jars to your local repository.
  • run maven ide, ide = [eclipse, idea, jbuilder] , if you use one of these ides.

This should be done for both the Common- and the ClientModule.

1.2 Editing the modules

Yourapp-Server

Actions and jsps

If required the actions (and so the JSPs) have to be changed so that all resulting data of an action, which are needed on the mobile client, are contained in the form.

Messages

If you want specific error messages from the exception you have to extend your exceptions from org.strutsme.server.BusinessException .

Yourapp-Common

  1. Create a package which contains the DTOs. In the following foo.dto is used.
  2. Every class, which is referenced by an attribute in a struts-form, has to satisfy one of the following conditions
    • the class derives from SerializationBase
    • the class has a substitute in the package configured by the attribute packagePrefix in the web.xml. This class must have the same classname. Also the propertynames and -types have to be equal.

Yourapp-Client

Remoteexecution

The client code can now call the action using org.strutsme.client.server.RemoteExecutor . The remote actioncall on the server must be implemented asynchron on the client. This means, the client cannot wait on the response of the server. Therefore a new thread is started for each remoteactioncall on the server. A sample is shown in listing Calling Action at Server 4. The listing is an extract of the sampleapplication StrutsME-Wishlist-Client in the package org.strutsme.client.adapter . The referenced runner in the listing has only to be implemented once for the clientapplication.

 
    /**
     * {@inheritDoc}
     */
    public void loadWish() throws AdapterException {
        SafeHashtable formParams = new SafeHashtable();

        Hashtable actionParams = new Hashtable();
        executeActionAtServer(GbCommonConstants.ACTION_WISH_LIST_WISHES,
                actionParams, formParams);
    }

    /**
     * {@inheritDoc}
     */
    public void saveArticle(final ArticleDtoImpl article) 
        throws AdapterException {
        SafeHashtable formParams = new SafeHashtable();
        Hashtable actionParams = new Hashtable();
        // put the article into the formData -> see 
        // ArticleForm  in the \yourappserverapplication
        formParams.put("article", article);
        formParams.put("body", article.getBody());
        formParams.put("subject", article.getSubject());
        String action = GbCommonConstants.
            ACTION_ARTICLE_SAVE_ARTICLE;

        executeActionAtServer(action, actionParams, 
            formParams);
    }

    /**
     * execute the action at the server.
     * @param action the action to perform
     * @param actionParams the actionparams for the server
     * @param formParams the formParams, which contains 
     * the real contentinformation
     * @throws AdapterException if the action could not 
     * be executed properly
     */
    private void executeActionAtServer(final String action,
            final Hashtable actionParams, 
            final SafeHashtable formParams)
            throws AdapterException {
        resetConnectionState();
        Thread thread = new Thread(new WishOnlineRunner(this, 
                action, actionParams, formParams));
        thread.start();
    }



Listing 4: Calling Action at Server

 
package org.strutsme.wishlist.client.adapter;

import java.util.Hashtable;

import org.strutsme.client.RemoteExecutor;
import org.strutsme.client.ServerResultWrapper;
import org.strutsme.common.SafeHashtable;
import org.strutsme.wishlist.client.control.ActionDispatcher;
import org.strutsme.wishlist.client.forms.FormTools;
import org.strutsme.wishlist.common.GbCommonConstants;

/**
 * Connections should be performed in seperate Threads to avoid deadlock. This
 * Runner handles all requests of the Wishlistapplication.
 * @author lbusmann
 */
public final class WishOnlineRunner implements Runnable {
    /**
     * the adapter, which started this runner.
     */
    private final WishOnlineAdapter adapter;

    /** the name of the action to perform. */
    private final String action;

    /** the requestParams for the action. */
    private final Hashtable requestParams;

    /** the content (formData) of the Action. */
    private final SafeHashtable formData;

    /**
     * Constructor.
     * @param action the action to perform
     * @param requestParams the requestParams
     * @param formData the formData
     * @param adapter the adapter, which started this runner
     */
    public WishOnlineRunner(final WishOnlineAdapter adapter,
            final String action, final Hashtable requestParams,
            final SafeHashtable formData) {
        this.adapter = adapter;
        this.action = action;
        this.requestParams = requestParams;
        this.formData = formData;
    }

    /**
     * {@inheritDoc}
     */
    public void run() {
        try {
            final SafeHashtable response = RemoteExecutor.executeAtServer(action
                    + GbCommonConstants.ACTION_EXTENSION, requestParams,
                    this.adapter.getSessionId(), formData);
            this.adapter.setLastServerResponse(new ServerResultWrapper(response));
        } catch (final Exception e) {
            FormTools.showErrorAlert("Wishlist",
                    "Can't connect to the server.\n\n"+e.getMessage());
        }
        ActionDispatcher.getInstance().executeResponseAction();
    }
}

Note that the WishOnlineRunner is calling the

Actiondispatcher.getInstance().executeResponseAction() , which would process the response of the server.

1.3 Bugs

This section contains information about known bugs or limitations of StrutsME .

Except for the session-id cookies are not handled. This could be improved by for example storing server cookies at the client in the RMS and sending these transparently to the server. The current solution for the application developer is to make sure that the web application also works without cookies.