Sunday, January 20, 2013

My Blog Moved to www.jiwhiz.com

Hi, from Oct 2012, I built my own personal blog website at www.jiwhiz.com, which is developed with Spring Framework, Spring Data, Spring Social, Spring Security, as well as Bootstrap, Thymeleaf, and deployed at CloudFoundry (hosted at www.appfog.com)

See the reasons I did that at http://www.jiwhiz.com/post/2012/10/My_First_Post.

Please visit my new blog site.

Monday, April 4, 2011

My First Impression of Spring Roo

In my previous post, I demonstrated how to set up a Web site with Spring Roo in 10 minutes. Actually I spent several hours to get it work, and even more to write it down and posted in my blog. For a beginner, it may take longer to understand the whole architecture and start to do real work. However, the beauty of Roo is you always have a running application to play with, and you can focus on learning one technology at a time, without being distracted by other things you are not familiar.

Here are what I like the Spring Roo:

First it fulfills my dream development environment. In my dream, I want to work with the best open source tools and best Java framework (in my opinion), such as Maven, Eclipse, Spring Framework. And I want to try the cutting edge technologies like GWT, OSGi. But I always get burnt by this ambition, it is impossible for me to learn all those and get my application work at once. Thanks to Roo Add-On Developers, I can use many new tools in an integrated running application before I even understand them.

Second, I like the round-trip rapid development process. You can use Roo to change your model, and Roo will update your Java code automatically. At the same time, you can also change your Java code, and Roo will automatically fix the generated aspect code and configurations. I also tried other tools before for generating project structure, such as AppFuse, Maven Archetype. They are good tool to start a project from scratch, but you cannot do it again with more changes. Now I can continuously use Roo to grow my application, and it really saves my time.

Third, I like the script approach. Roo will keep a log file at the project folder (log.roo) with all your commands. After several round of exercises, you can just copy the script from log.roo and modify it to have a clean model, then ask Roo to run it again from scratch. I find it is very useful when I design the domain model. Other RAD tools may use UML to do the same, but I feel UML Diagram is better for communicating among people. When get down to code level, text based script is superior for talking to computer.

Last, I love the code it generates, beautiful code. Roo uses AspectJ inter type declaration (ITD) feature to hide all those boilerplate code, so the generated Java code will be very clean. After you understand how it works, you won't want to go back to the old way.

After first try of Spring Roo, I think it will be useful in two areas:

  • Rapid Prototyping. Right now as an application designer, after discussing with business, it will take me many days to build the domain model and mock up UI. When the first approach is not right (always happen), I have to throw away old code and write those boilerplate code again and again. Roo can help me build a prototype quicker, especially for domain model part.
  • Standard Application Architecture. I didn't try Add-On development, but I assume it is doable to customize Roo so it will generate code following standard in any enterprise. Therefore in any corporation, it will be very fast to start a new project, and let developer focus the business issues instead of infrastructure issues.

Here is my wish list for Spring Roo:

  • Provide richer script command to build complete domain model. It has excellent support for Entity, little support for Value Object or Domain Service. I want Roo to generate methods for me as well.
  • Support Maven structure for multiple projects. Currently seems Roo only supports one project structure. For a medium to large application, we may have to split code into several projects. Hope Roo will support it in the future.
  • Better support to Google App Engine and GWT. I will try it when 1.1.3 is released.
  • See what Roo can do after it integrates with WaveMaker. If UI design is as quick and clean as this, I can talk to customer and build running demo on the fly. That's my biggest dream.

Overall, my first impression of Spring Roo is very good. I appreciate SpringSource for providing this wonderful tool for Java developers. They are the true leader in Java Open Source Community.

Sunday, April 3, 2011

Build Open Toast Web Site with Spring Roo in 10 Minutes

Two weeks ago, I started to learn Spring Roo by its reference document and tutorials. Now it is time to do some real exercises.

After reading Ben Alex's blog about his Wedding RSVP Web site, I want to do a similar Web site for Toastmasters.

The main goal for this exercise is to register our club members' personal data and confirm their email address. The process is very simple: admin user can login and register new member; a confirmation email will be sent out to new member's email address; new member clicks the hyperlink in the email to confirm the registration.

I opened STS 2.6.0 with Spring Roo 1.1.2, and followed Ben's tutorial. After a while I got this Roo script to set up my project:

project --topLevelPackage com.opentoast --projectName OpenToast --java 6
persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY

entity --class ~.domain.Toastmaster --testAutomatically 
field string --fieldName firstName --sizeMin 2 --sizeMax 30
field string --fieldName lastName --notNull --sizeMin 2 --sizeMax 30
field string --fieldName email --sizeMax 30 --sizeMin 6
field string --fieldName phone --sizeMax 20
field boolean --fieldName confirmed

entity --class ~.domain.EmailConfirmation
field string --fieldName code --notNull 
field string --fieldName email --notNull
field date --fieldName confirmDate --type java.util.Date
field reference --fieldName toastmaster --type ~.domain.Toastmaster --notNull 
finder add --finderName findEmailConfirmationsByCodeEquals

interface --class ~.domain.ConfirmationService
class --class ~.domain.impl.ConfirmationServiceImpl

controller scaffold --entity ~.domain.Toastmaster --class ~.web.ToastmasterController
controller class --class ~.web.ConfirmationController

selenium test --controller ~.web.ToastmasterController

logging setup --package WEB --level DEBUG

security setup

email sender setup --hostServer smtp.gmail.com --protocol SMTP --port 587 --username youraccount --password yourpassword
field email template --class ~.domain.impl.ConfirmationServiceImpl

perform eclipase

The domain model only contains two entity, Toastmaster and EmailConfirmation. (I cannot use Member or User, since those are reserved SQL keyword.)

One Web controller for maintaining Toastmaster records is genereated by controller scafford command. Spring Roo will generate all CRUD jsp pages.

Another controller for new member to confirm email address made by: controller class --class ~.web.ConfirmationController.

When admin user creates a new Toastmaster, a confirmation email will be sent out, and I want this logic to be in a service, so one service interface and one implementation class are created. But Spring Roo cannot generate real business logic code for us, so I have to add code manually to interface and implementation classes.

There are other changes in this application to get it working as we want. Because the last step in Roo script is perform eclipse, so just run this script in Roo and import the result project to STS, you have a running Web application ready to play with.

So first let's add logic to ConfirmationService:

src/main/java/com/opentoast/domain/ConfirmationService.java

package com.opentoast.domain;

public interface ConfirmationService {
    void sendConfirmationEmail(Toastmaster toastmaster);
}

src/main/java/com/opentoast/domain/impl/ConfirmationServiceImpl.java

package com.opentoast.domain.impl;

import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.stereotype.Component;

import com.opentoast.domain.ConfirmationService;
import com.opentoast.domain.EmailConfirmation;
import com.opentoast.domain.Toastmaster;

@Component("confirmationService")
public class ConfirmationServiceImpl implements ConfirmationService{
    @Autowired
    private transient MailSender mailTemplate;

    public void sendMessage(String mailFrom, String subject, String mailTo, String message) {
        org.springframework.mail.SimpleMailMessage simpleMailMessage = new org.springframework.mail.SimpleMailMessage();
        simpleMailMessage.setFrom(mailFrom);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setTo(mailTo);
        simpleMailMessage.setText(message);
        mailTemplate.send(simpleMailMessage);
    }

    @Override
    public void sendConfirmationEmail(Toastmaster toastmaster) {
        //create a new email confirmation record
        EmailConfirmation emailConfirmation = new EmailConfirmation();
        emailConfirmation.setCode(UUID.randomUUID().toString());
        emailConfirmation.setEmail(toastmaster.getEmail());
        emailConfirmation.setToastmaster(toastmaster);
        emailConfirmation.persist();
        
        //build email content
        StringBuffer sb = new StringBuffer();
        sb.append("Please confirm your email address '");
        sb.append(toastmaster.getEmail());
        sb.append("' by clicking http://localhost:8080/OpenToast/confirmation/");
        sb.append(emailConfirmation.getCode());
        sb.append("\n Thank you!");
        sb.append("\n\nOpen Toast Project");
        
        sendMessage("Open Toast Project <opentoastproject@gmail.com>", "Please Confirm Your Email to Open Toast", toastmaster.getEmail(), sb.toString()); 
    }

}

The ConfirmationServiceImpl is a component (annotated by @Component), so we don't need to change any configuration, and it will be automatically handled by Spring container. Next, inject this component to ToastmasterController so when admin creates a new member, it will use this service to send out email. Add create method to ToastmasterController class, and Spring Roo will automatically remove same method in aspectj file ToastmasterController_Roo_Controller.aj.

src/main/java/com/opentoast/web/ToastmasterController.java

package com.opentoast.web;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.roo.addon.web.mvc.controller.RooWebScaffold;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.opentoast.domain.ConfirmationService;
import com.opentoast.domain.Toastmaster;

@RooWebScaffold(path = "toastmasters", formBackingObject = Toastmaster.class)
@RequestMapping("/toastmasters")
@Controller
public class ToastmasterController {

    @Autowired
    private transient ConfirmationService confirmationService;

    @RequestMapping(method = RequestMethod.POST)
    public String create(@Valid Toastmaster toastmaster, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            uiModel.addAttribute("toastmaster", toastmaster);
            return "toastmasters/create";
        }
        uiModel.asMap().clear();
        toastmaster.persist();
        confirmationService.sendConfirmationEmail(toastmaster);
        
        return "redirect:/toastmasters/" + encodeUrlPathSegment(toastmaster.getId().toString(), httpServletRequest);
    }

}

Here we only add code to inject ConfirmationService object, and call its sendConfirmationEmail methos when a new Toastmaster record is created.

The email contains a URL, and when new member clicks this URL, it will send HTTP GET request with the confirmation code in it. Spring MVC can handle it very nicely with URL Template /confirmation/{code}, so the code value is bound to parameter String code. By using Roo auto generated finder method EmailConfirmation.findEmailConfirmationsByCodeEquals, we can get the EmailConfirmation object used for this confirmation, and set the confirmation date, set Toastmaster object as confirmed.

So in ConfirmationController class, remove all generated methods, and add confirmByCode method to do the logic:

src/main/java/com/opentoast/web/ConfirmationController.java

package com.opentoast.web;

import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.opentoast.domain.EmailConfirmation;

@RequestMapping("/confirmation/**")
@Controller
public class ConfirmationController {
    @RequestMapping(value="/confirmation/{code}", method=RequestMethod.GET)
    public String confirmByCode(@PathVariable String code, ModelMap modelMap) {
        try {
            EmailConfirmation emailConfirmation = (EmailConfirmation)EmailConfirmation.findEmailConfirmationsByCodeEquals(code).getSingleResult();
            emailConfirmation.setConfirmDate(new Date());
            emailConfirmation.getToastmaster().setConfirmed(true);
            emailConfirmation.persist();
            
            modelMap.put("confirmation", emailConfirmation);
        } catch (Exception e) {
            // ignore
        }
        return "confirmation/thanks"; 
    }

}

After member clicks URL, we want to display a thank you message, so let's change the generated index.jspx name to thanks.jspx in confirmation folder, and add a spring message:

src/main/webapp/WEB-INF/views/confirmation/thanks.jspx

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <jsp:output omit-xml-declaration="yes"/>
  <spring:message code="label_confirmation_index" htmlEscape="false" var="title"/>
  <util:panel id="title" title="${title}">
    <spring:message code="application_name" htmlEscape="false" var="app_name"/>
    <h3>
      <spring:message arguments="${app_name}" code="welcome_titlepane"/>
    </h3>
    <p>
      <spring:message code="thanks_text" arguments="${confirmation.email}"/>
    </p>
  </util:panel>
</div>

In order to display the message, we add the text to messages.properties:

src/main/webapp/WEB-INF/i18n/messages.properties

thanks_text=You have successfully confirmed your email {0}. Thank you for signing up Open Toast.

And update view.xml to reflect the name changes:

src/main/webapp/WEB-INF/views/confirmation/views.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>
    <definition extends="public" name="confirmation/thanks">
        <put-attribute name="body" value="/WEB-INF/views/confirmation/thanks.jspx"/>
    </definition>
</tiles-definitions>
pr/> last change is to security setting. The whole Web site should only be accessed by authenticated user. We only allow admin user to maintain Toastmaster data in toastmaster path, but un-authenticated user can access confirmation path to confirm.

src/main/resources/META-INF/spring/applicationContext-security.xml

...
<!-- HTTP security configurations -->
    <http auto-config="true" use-expressions="true">
        <form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t"/>
        <logout logout-url="/resources/j_spring_security_logout"/>
        
        <!-- Configure these elements to secure URIs in your application -->
        <intercept-url pattern="/toastmasters/**" access="hasRole('ROLE_ADMIN')"/>
        <intercept-url pattern="/confirmation/**" access="permitAll" />
        <intercept-url pattern="/resources/**" access="permitAll" />
        <intercept-url pattern="/login**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
    </http>
...

If you didn't change gmail account ID and password, you can open email.properties file and update with your personal gmail account and password.

So that's it. You can test this Web application by running mvn tomcat:run in the directory you run the Roo script, and open http://localhost:8080/OpenToast. First login with admin account and add a new Toastmaster with a valid email address. Then check the email, and click the URL, you will see the thank you page. Go back to the Web site and list all Toastmasters, you will see the confirmed flag is true now.

Wednesday, December 30, 2009

Eclipse UML2 Tools is Good

oodThis week I'm reading the book UML for the IT Business Analyst, and following its instructions to do requirement analysis.

I had used Enterprise Architecture long time ago, and I like it very much. Unfortunately, it is a commercial product, and expensive. Since I'm working on this open source project, I want every tool used is open sourced. I tried ArgoUML  sometime ago, a very famous open source UML tool, but was not satisfied.
I know Eclipse has a UML2 project under Modeling Project and a graphic tool project to draw UML2 models. I checked again and found out UML2 Tools already released 0.9 this summer. So I followed this tutorial to install and use the tool. I'm very impressed by this Eclipse UML2 Tools, and think it is good enough for UML modeling.

The graphic is pretty neat, and consistent with the whole Eclipse style. For example the use case diagram:





I appreciate the feature that you can save the diagram as SVG file, so I can post very big diagram to internet as SVG files, because all browsers now support SVG. So if you click the picture, you can view the more clear diagram in browser.

Here is the activity diagram for Manage Meeting business use case.


The Partition is very cool. The only issue is I can only layout partition horizontal, which is not the same as examples I see. And it is not convenient to view in browser or printed document.


The class diagram is also beautiful:


It is amazing that such a good tool is free and open sourced. Many thanks to Eclipse Modeling Team!

Friday, December 18, 2009

You Believe You Know What You Want Until You Start To Write It Down

I had the idea to build a web site for our toastmaster club a year ago. This Open Toast Project was created last Nov, and there is very little progress. Many reasons (or excuses) for that, but time is the most critical one. This Christmas I take three weeks super long holiday, so I can have some days to focus on the project, hoping to achieve something.

I have been in Toastmaster for about 2 and half years now, and have been the President of TM4PM club for more than a year. With a little confidence, I believed I understood the business of a small toastmaster club fairly well, until I tried to write down the requirements.

Since I don't have much time working on the project, I want to make it very simple, just to solve the problem of scheduling club meetings. As a club VP Education, the job mainly is setting up weekly meetings, assigning meeting roles to members. Currently we use emails to communicate with each other, and it works pretty well, most of the time. The problem occurs when something unexpected happens, such as members go vacation or business trip, have heavy work load, or family issues, health issues, so that they cannot participate. VP Education or meeting toastmaster will have big headache to fill the missing roles. If, and only if, we have an on-line application that allow us to sign up meeting role, confirm attendance, monitor meeting status, life will be a lot easier.

So the first requirement is As a member, I can sign up a role in a meeting. Okay, that sounds simple.

We have Member business object now, and the member is also the user of the system. Member can assign meeting role to himself/herself. And we also want VP Education or Executive Members can assign meeting role to other members. Member or Executive Member are Actors, and Executive Member is a specialized Member.

Where are those member information? They are spread out among Guest Cards, pieces of paper, emails, everyone's contact lists, or memories. So often the meeting toastmaster couldn't get confirmation from members because no contact info available. Since Toastmaster is a self-motivated education, the turn-over rate is extremely high, more than 70%. Even executives can suddenly disappear. If, and only if, we can manage our members contact info, life will be a lot easier.

So we have 2 new requirements, As an executive member, I can register member and As a guest, I can self register to be a member. There may be more requirements about managing members, assigning executive position to members, but I want to keep it simple, so let's add them in the future.

We still need one more requirement, As an executive member, I can assign meeting roles to other members. Usually it's VP Education's responsibility, but other executives have to take over the task sometimes. Maybe we can use delegation mechanism, so VP Education can delegate this job to other members. But I want to keep it simple, that is all executive members can do the job.

Member and Executive Member are Actors in the context of Club. Wait, I belong to two clubs. I'm the President of TM4PM, and a normal active member of Dawnbreakers. I'm also a regular guest to two other clubs, CU@Noon and Paragon. I want to see all the meeting schedules from clubs that I'm associated with, so I can prepare the speeches or meeting roles assigned to me. We have to separate User from Member. A user of this system can be member of many clubs, and may have different position/status in each club. So we have to manage clubs, let user join clubs. Oh my, it is never simple anymore. I can see the security will be a big challenge.

This system will work well only if everyone is using it. Remember the requirement As an executive member, I can register member. Since we separate user from member, I prefer to give user more control, like which club to join, or just watch club activities, sign up a meeting role, etc. Maybe it will cause problem when someone starts to abuse the system, but right now I assume we are good citizens, and put all those hard issues to the future release, if I can ever release something.

Let me organize my thoughts and list all the features:

  1. As a new user, I want to register myself to the system.
  2. As a user, I want to easily find a club, join a club and quit a club.
  3. As a user, I want to easily view all my toastmaster meeting agendas from joined clubs.
  4. As a club member, I want to sign up a meeting role in future meetings.
  5. As a club executive, I want to plan meeting agenda, assign roles to members.
  6. As a user, I want to manage my contact info or profile.
There are many other features to think about, like manage club info, manage club member, manage executive team, etc, etc... I have to stop thinking now. Even above feature list I don't think I can do them all at once.

The feature list is the high level business requirement, and I try to segment it into system use cases. Like the title says, I believe I know what I want, until I start to write it down. basically I'm facing two challenges:

First, how to balance current needs with long term vision. I have been doing VP Education job for quite a while, and understand current workflow. The leader, usually VP Education, assign the meeting roles, or ask for volunteers, through email or signup sheet during meetings. To automate the process on-line is hard, because you have to shift control from the leader to the members, so the members have the final say to the signup sheet, the leader is just a coordinator. That is process re-engineering. Besides, we have a bigger vision, to let users manage the clubs they join or watch, so they can monitor all meetings they are interested. In the future, we can add more features like user can track educational progress in Toastmaster designations, or people can give feedback to speakers, etc, etc. Whenever I think about the bigger picture, the scope easily explodes, and I get overwhelmed.

Second, how to balance analysis with design and technical details. I'm a user of this system, and a developer to design/implement the system. Now I'm trying to analyze the requirements, but I spend lots of time imagining the user interface and system architecture, dreaming how I can use GWT + Spring to build a cool RIA. This feeling drags me to the Eclipse to start writing code. But I know I will be stuck with all kinds of technical details, and will lose focus of requirements. I believe analysis and design are closely bound together in order to build a good software. however my goal is to get requirements done, so better write text instead of code.

During the use case analysis, I find it is a blessing to be a programmer as well. I can identify which request is doable even it seems too fancy, and which request is very hard to implement. That helps me to prioritize the feature requests, so the project scope is under my control. It is interesting that I'm also considering project management issues.

Writing down my thoughts in English is much more difficult than writing Java code, and it needs great perseverance to continue. I feel my mind is clearer after this blog, and it is fun to share with others.

Sunday, November 29, 2009

We are 64bit ready, or not?

I got my new DELL XPS 9000 this week after long waiting, and started playing with it with great enthusiasm this weekend.

The computer will be my primary development desktop at home, so I have to install all my toolkits. I'm tired of OutofMemoryException while coding under 32bit OS, and finally I can have more heap size in JVM with this new 64bit powerful machine. :)

First step was very smoothly, I installed JDK 1.6.0_17 from Sun Java Website, and it has Windows x64 vesion.

Next step was to install my favorite IDE, Eclipse for Java EE Developers (Galileo). Wait, I couldn't find 64bit download! I can see 64bit version for Linux, Mac Cocoa, but not for Windows. There is only eclipse-jee-galileo-SR1-win32.zip. I downloaded this one, and obviously Eclipse gave me Exception!

Fortunately, someone already figured out and blogged about it. OK, let's download 64bit version of Eclipse SDK, and install my plugins one-by-one. After a really boring setup process, I got my Eclipse running under 64bit JDK!

Then it was time to install my favorite build tool - Maven. Very straightforward. After setting up environment variables, I can run mvn in command line.

At last, I wanted to try GWT with all of those tools, and that really pissed me off. I went through GWT Experience - Create GWT Module Project with Maven GWT Plugin. And I got compiler error when I tried to run the GWT application by Maven:

[INFO] [gwt:run {execution: default-cli}]
[INFO] using GWT jars from project dependencies : 1.7.1
[INFO] Unpack native libraries required to run GWT
[INFO] establishing classpath list (scope = runtime)
[INFO] create exploded Jetty webapp in C:\GWT\test\org.opentoast.admin\war
[INFO] auto discovered modules [org.opentoast.admin.Application]
[ERROR] You must use a 32-bit Java runtime to run GWT Hosted Mode.
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------

What a surprise!

Googling, Googling, and I realized it is the problem in GWT 1.x. This has been raised as issue 134, issue 135, or issue 2880. Here is a good explanation from Dan Morrill at GWT Forum. So basically I have to wait until GWT 2.0 comes out with Out-of-process Hosted Mode (OOPHM) to get 64 bit support. Even right now GWT 2.0 RC2 is here to try, I still cannot use it with Maven, because gwt-maven-plugin won't work, I have to wait for a while until both are released.

Seems the only solution is to switch to 32bit JDK, and use all 32bit tools now. What a waste of time! Well, that's the price I have to pay when I play with new technologies.

Wednesday, November 11, 2009

GWT Experience - Create GWT Module Project with Maven GWT Plugin

I Have played with GWT for quite a long time, reading the book "GWT in Action", trying Tutorials and many blogs (Deploying GWT Applications in SpringSource dm Server, etc.)

Now I feel it is time to add rich client UI to Open Toast project.

Use Maven GWT plugin to create GWT module project

There are many ways to create a GWT application from scratch. Normally people use webAppCreator tool in command line, or use Google Plugin for Eclipse. The problem is the brand new application created by Google tools has different directory and package layout from other Open Toast modules.

We all know Convention over Configuration, and the question is whose convention we follow? Seems GWT team is not following Maven's convention (as far as GWT 1.7.x). But I want to make our development/build/deployment be consistent with Maven, for long term benefit. Fortunately, there is a Maven plugin Mojo Maven GWT Plugin or "gwt-maven-plugin" to solve the problem.

Since release 1.1, mojo gwt-maven-plugin merged with Google Code GWT-maven-plugin, and it is pretty stable now.

So first, I tried to create our administration by gwt-maven-plugin archetype. Inside opentoast root folder, run the command:

mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo -DarchetypeArtifactId=gwt-maven-plugin -DarchetypeVersion=1.1 -DgroupId=org.opentoast -DartifactId=org.opentoast.admin

During creation, set project version to 0.0.2, and package to org.open.toast.admin. After that I have to change several settings in pom.xml. The gwt.version is changed to 1.7.1, the current release; and gwt-maven-plugin version is changed to 1.1 instead of 1.1-SNAPSHOT.

Then I can test the new admin application in hosted mode by command:

mvn -DrunTarget=org.opentoast.admin.Application/Application.html gwt:run

A very simple Web application with just a line of text.

The whole project structure is very consistent with standard Maven project layout, such as src/main/java, src/main/resources, src/main/webapp. But there are still 2 issues I don't feel comfortable with. First, the GWT XML module file is put inside java folder, at src/main/java/org/opentoast/admin/Application.gwt.xml. Second, html and css files are inside resources folder instead of webapp. Application.html and Application.css are located at src/main/resources/org/opentoast/admin/public folder.

From GWT Developer Guide - "Modules: Units of configuration", we know public sub-package under module xml file's located package contains static resources used by the GWT module. Since client code may reference those resources by GWT.getModuleBaseURL() + "resourceName.png", I think better we keep it.

For first issue, I tried to move Application.gwt.xml to resources folder, at src/main/resources/org/opentoast/admin/Application.gwt.xml, and I can still run application in hosted mode, so maybe it is OK to do that.

Rename module name

After running the application in hosted mode, GWT created a folder war in root directory, and compiled Java code into Javascript. The generated Javascript file org.opentoast.admin.Application.nocache.js was put inside war/org.opentoast.admin.Application/ folder. Seems the GWT module name is org.opentoast.admin.Application, which is too long with full package name. It is very easy to change it to a much shorter name admin.

First, update GWT module xml file by adding rename-to attribute to module element:


....

Next, update Application.html to load correct js file:


Try to launch the application by mvn -DrunTarget=admin/Application.html gwt:run, and it works fine. There is new folder admin inside war, with all public resources and generated js file admin.nocache.js.

Later I tried to integrate this GWT project into the bigger Open Toast Project with quite a few small challenges, and that will be my next blog.