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.

Saturday, September 19, 2009

RESTful Web Services with Spring 3 Experience

Arjen Poutsma introduced REST support in Spring 3 through his two blogs REST in Spring 3: @MVC and REST in Spring 3: RestTemplate. Follow his instructions and Spring 3 PetClinic sample application, I got RESTful Web Service working in my Open Toast Project.

Just to provide a very simple service "get member object by member id", I created a new Web bundle project "org.opentoast.rest" by copying "org.opentoast.web" project. There is only one Java class in new project, MemebrController:

@Controller
public class MemberController
{
    protected final Log log = LogFactory.getLog(getClass());
    
    private MemberManager memberManager;
    
    @Autowired
    public MemberController(MemberManager memberManager){
        this.memberManager = memberManager;
    }
    
    @RequestMapping(value="/members/{memberId}", method = RequestMethod.GET)
    public ModelAndView getMember(@PathVariable("memberId") Long id) {
        Member m = memberManager.getMemberById(id);
        ModelAndView mav = new ModelAndView("member");
        mav.addObject("member", m);
        return mav;
    }
}

It provides one RESTful service in the method getMember(). It is annotated by @RequestMapping with URI template /members/{memberId}. Using @PathVariable("memberId"), the request member id is passed to parameter id. So with the injected MemberManager, we can get the Member object by id and pass to returned ModelAndView object. The view name is "member", and result member object is put into model with key "member" as well.

To setup REST support, there are few changes in config file module-context.xml:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:oxm="http://www.springframework.org/schema/oxm"
  xsi:schemaLocation="
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
   http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

 <context:component-scan base-package="org.opentoast.rest.controller"/>

 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
   
 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
 
 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
 
 <bean id="member" class="org.springframework.web.servlet.view.xml.MarshallingView">
  <property name="contentType" value="application/vnd.opentoast.rest+xml"/>
  <property name="marshaller" ref="marshaller"/>
  <property name="modelKey" value="member"/>
 </bean>

 <oxm:jaxb2-marshaller id="marshaller">
  <oxm:class-to-be-bound name="org.opentoast.domain.Member"/>
 </oxm:jaxb2-marshaller>

</beans>

Since we only want to support REST service with customized content type, we don’t need ContentNegotiatingViewResolver , so only one view resolver is set in the context: org.springframework.web.servlet.view.BeanNameViewResolver. It will resolve view named "member" to bean "member", which is an instance of org.springframework.web.servlet.view.xml.MarshallingView. The content type is "application/vnd.opentoast.rest+xml", modelKey is "member" and reference to jaxb2 marshaller bean "marshaller".

The web.xml sets servlet with org.springframework.web.servlet.DispatcherServlet, named opentoastrest, and maps to /*:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">

 <display-name>Open Toast RESTful</display-name>

 <context-param>
  <param-name>contextClass</param-name>
  <param-value>com.springsource.server.web.dm.ServerOsgiBundleXmlWebApplicationContext</param-value>
 </context-param>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   /META-INF/spring/module-context.xml
   /META-INF/spring/osgi-context.xml
  </param-value>
 </context-param>

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <servlet>
  <servlet-name>opentoastrest</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value></param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>opentoastrest</servlet-name>
  <url-pattern>/*</url-pattern>
 </servlet-mapping>
</web-app>

You can check out the code from Google Code by running

svn checkout http://opentoastproject.googlecode.com/svn/tags/opentoast_20090919 opentoast

Then inside opentoast folder, run

mvn package

to build the whole application. Copy the par file at opentoast/org.opentoast.par/target/OpenToast.par to springsource dm Server pickup folder, and start dm Server.

To test the RESTful Web Service, here is a client example code:

package org.opentoast.client;

import java.util.HashMap;
import java.util.Map;

import org.opentoast.domain.Member;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.client.RestTemplate;

public class RestClient
{
    RestTemplate restTemplate;
    
    public RestClient(RestTemplate template)
    {
        this.restTemplate = template;
    }
    
    public void testMember()
    {
        Map<String, String> vars = new HashMap<String, String>();
        vars.put("memberId", "1");
        Member result = restTemplate.getForObject(
                "http://localhost:8080/opentoastrest/members/{memberId}",
                Member.class, vars);
        System.out.println(result);
    }
    
    public static void main(String[] args)
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                "/org/opentoast/client/appContext.xml");
        RestClient client = (RestClient)ac.getBean("restClient");
        client.testMember();
    }
}
With xml config file /org/opentoast/client/appContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:oxm="http://www.springframework.org/schema/oxm"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

 <bean id="restClient" class="org.opentoast.client.RestClient">
  <constructor-arg ref="restTemplate"/>
 </bean>

 <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
  <property name="messageConverters">
   <list>
    <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
     <constructor-arg ref="marshaller"/>
     <property name="supportedMediaTypes">
      <list>
       <bean class="org.springframework.http.MediaType">
        <constructor-arg value="application"/>
        <constructor-arg value="vnd.opentoast.rest+xml"/>
       </bean>
      </list>
     </property>
    </bean>
   </list>
  </property>
 </bean>

 <oxm:jaxb2-marshaller id="marshaller">
  <oxm:class-to-be-bound name="org.opentoast.domain.Member"/>
 </oxm:jaxb2-marshaller>
 
</beans>
Run this test client program and you will get print out:

[Member 1: Jane Smith]

One big question I have now is "Do I need to expose my rich domain model as REST object model?"

JAXB2 marshaller requires Member class to be annotated with @XmlRootElement. And my domain model class Member is already annotated with persistent API, so now it looks like:

@XmlRootElement
@Entity
@Table(name = "MEMBER")
public class Member extends BaseEntity
{
...

If I don't want REST client to see my rich domain model, I have to use DTO model, and map between those two models. That will defeat the purpose of Domain Driven Design. If I expose my rich domain model classes to client, it will be more problematic when I try to use GWT as client application running inside browser. So far I haven't found a good solution for GWT + REST.

Monday, September 14, 2009

Release s2dm Maven Plugin 0.0.3

Open Toast Project Maven Plugin for Spring Source dm Server Development 0.0.3 was released.

After Spring Bundlor released 1.0M5, I tried and got it working with my project.

Still have trouble with M2Eclipse, the Maven Dependencies classpath of web project doesn't include depending projects in workspace (domain and service projects). So I have to manually add those two projects to web project Java Build Path.

The 0.0.3 release can be used to set up Eclipse workspace, and build par.

To use that plugin, in parent pom.xml, setup plugin repository to

 <pluginRepositories>
  <!-- Maven 2 Plugin for S2DM -->
  <pluginRepository>
   <id>opentoast.maven.s2dm.plugin</id>
   <url>http://opentoastproject.googlecode.com/svn/mavenrepo</url>
  </pluginRepository>
 
  <!-- SpringSource milestone -->
  <pluginRepository>
   <id>com.springsource.repository.bundles.milestone</id>
   <name>SpringSource Enterprise Bundle Repository</name>
   <url>http://repository.springsource.com/maven/bundles/milestone</url>
  </pluginRepository>

 </pluginRepositories>

So go to project root directory /opentoast, and type

mvn org.opentoast:maven-s2dm-plugin:0.0.3:eclipse

It will generate all eclipse setting files, such as /project, .classpath, .settings/org.eclipse.wst.common.project.facet.core.xml, etc. It also generates a dummy MANIFEST.MF file at generated/META-INF/MANIFEST.MF under each bundle project folder. The trick is the .classpath will include the generated folder as classpathentry, so STS bundlor will automatically update it with template.mf settings.

To build the whole application into a par, just type mvn package under opentoast, it will use dm-par goal to package par artifact.

So far STS does not work with dm Server 2.0.0.M4, so I just use STS to edit code, and use command line to build par, then deploy to local running dm Server pickup folder. I will try to get the application running inside STS later. Hope dm Server and Spring 3 can be released before Christmas, so I can play with them during winter break.

Tuesday, August 11, 2009

Surprise: SpringSource was acquired by VMware.

While I was struggling with migrating my project to SpringSource dm Server 2.0 since last week, this Monday I heard the big news VMware to Acquire SpringSource with more than $400 million! What a surprise!

This is really a good news to SpringSource, and I only wish those key developers would not take the cash and go vacation forever. :)

I finished migrating Open Toast Project to dm server 2.0.0.M4 tonight. Last issue was solved with the help from Andy Wilkinson. The support from Spring community is awesome.

I will try to blog more about my experience of Bundlor and Web bundle later and polish my maven plugin for 0.0.3 release.

Monday, May 4, 2009

Setup Development Environment

My dream development environment consists of all open source tools:

  • Eclipse as IDE
  • Maven as build tool
  • Subversion as source code control
  • And an open source server: SpringSource dm Server

Recently there are many interesting announcements from SpringSource, like Spring dm Server 2.0M1, Spring Roo. I don't have time to follow those new trends, especially when they are just in alpha or beta stages. I want to focus on business application development and get my project done. So I just pick the released products from Open Source world, like dm Server 1.0.2.RELEASE.

I spent some time on BND and Maven Bundle Plugin, and tried to generate manifest from maven pom, but found it is too hard. SpringSource dm Server has an issue with Hibernate, you have to add "import-scope:=application" and put all bundles into a par file. See my questions at forum Where is the documentation about "import-scope:=application"?

Bundlor from SpringSource is also interesting, but I don't have time to learn another beta product, so I choose to manually create/maintain manifest files. Ideally I want to put all dependency info into pom, and derive manifest from pom. Maybe I will try again after Bundlor and dm Server 2.0 release after summer.

In order to continue my project, I just cleaned up my S2DM Maven plugin code and released 0.0.2. Open Toast Maven Plugin for SpringSource dm Server 0.0.2 has 2 goals now, one is to setup Eclipse config for OSGi projects, another is to generate par file. I code the plugin for Open Toast project, but it is generic enough for all Web application based on SpringSource dm Server. So feel free to use it and give me feedback.

Here is a brief description about how to setup environment for Open Toast Project:

1. Download and install Eclipse Ganymede SR2.

2. Install Subclipse eclipse plugin from http://subclipse.tigris.org/update_1.6.x

3. Install Spring IDE 2.2.2 and dm Server Tools 1.1.2 from http://www.springsource.org/update/e3.4. I have problem with dm Server Tools 1.1.3M1, but 1.1.2 seems very stable.

4. Download and unzip SpringSource dm Server 1.0.2.RELEASE, and set up a server runtime in Eclipse at localhost.

5. In Eclispe, open dm Server Repository Browser and download required dependencies:

  • Hibernate JPA Library 3.3.2.GA. It will include related bundles.
  • CGLIB 2.1.3. Not sure why it is not included in Hibernate library.
  • dbcp 1.2.2.osgi
  • commons.pool 1.4.0
  • hsqldb 1.8.0.9

6. Check out code from Google Code by any SVN client application, like TortoiseSVN, the url is http://opentoastproject.googlecode.com/svn/trunk/opentoast. You can also add svn repository for this url in Eclipse.

7. In command line, go to root directory of downloaded project, with parent pom.xml and 5 sub folders, run mvn org.opentoast:maven-s2dm-plugin:0.0.2:eclipse to set up eclipse config. Then import all projects into Eclipse. It may take a while to build those projects inside eclipse, and finally all compiler errors should be resolved.

8. In Eclipse, add org.opentoast.par into SpringSource dm Server v1.0 at localhost, and start the server. The console will display:

[2009-05-04 19:18:48.296] main                      Server starting.
[2009-05-04 19:18:49.365] main                      OSGi telnet console available on port 2401.
[2009-05-04 19:18:53.191] main                      Boot subsystems installed.
[2009-05-04 19:18:55.266] main                      Base subsystems installed.
[2009-05-04 19:18:57.053] server-dm-14              Installing profile 'web'.
[2009-05-04 19:18:58.737] server-dm-14              Installed profile 'web'.
[2009-05-04 19:18:58.944] server-dm-5               Creating HTTP/1.1 connector with scheme http on port 8080.
[2009-05-04 19:18:58.995] server-dm-5               Creating HTTP/1.1 connector with scheme https on port 8443.
[2009-05-04 19:18:59.028] server-dm-5               Creating AJP/1.3 connector with scheme http on port 8009.
[2009-05-04 19:18:59.072] server-dm-5               Starting ServletContainer.
[2009-05-04 19:18:59.892] server-dm-6               Server open for business with profile 'web'.
[2009-05-04 19:19:00.558] Deployer Recovery         Creating web application '/'.
[2009-05-04 19:19:00.936] async-delivery-thread-1   Starting web application '/'.
[2009-05-04 19:19:03.158] Deployer Recovery         Deployment of 'com.springsource.server.servlet.splash' version '1.0.2.RELEASE' completed.
[2009-05-04 19:19:03.526] Deployer Recovery         Creating web application '/admin'.
[2009-05-04 19:19:03.850] async-delivery-thread-1   Starting web application '/admin'.
[2009-05-04 19:19:04.377] Deployer Recovery         Deployment of 'com.springsource.server.servlet.admin' version '1.0.2.RELEASE' completed.
[2009-05-04 19:19:04.391] fs-watcher                Processing 'INITIAL' event for file 'server.admin.splash-1.0.2.RELEASE.jar'.
[2009-05-04 19:19:04.399] fs-watcher                File 'server.admin.splash-1.0.2.RELEASE.jar' already deployed.
[2009-05-04 19:19:04.404] fs-watcher                Processing 'INITIAL' event for file 'server.admin.web-1.0.2.RELEASE.jar'.
[2009-05-04 19:19:04.412] fs-watcher                File 'server.admin.web-1.0.2.RELEASE.jar' already deployed.
[2009-05-04 19:19:09.200] nection(2)-192.168.0.100  Creating web application '/opentoast'.
[2009-05-04 19:19:12.528] service-monitor-thread-1  Mandatory reference '&memberRepository' in bundle 'org.opentoast.par-0.0.1-org.opentoast.service' version '0.0.1' is waiting for service with filter '(&(objectClass=org.opentoast.domain.MemberRepository)(com.springsource.server.app.name=org.opentoast.par-0.0.1))'.
[2009-05-04 19:19:12.533] service-monitor-thread-1  Mandatory reference '&entityManagerFactory' in bundle 'org.opentoast.par-0.0.1-org.opentoast.service' version '0.0.1' is waiting for service with filter '(&(objectClass=javax.persistence.EntityManagerFactory)(com.springsource.server.app.name=org.opentoast.par-0.0.1))'.
[2009-05-04 19:19:12.830] server-dm-11              Reference '&entityManagerFactory' in bundle 'org.opentoast.par-0.0.1-org.opentoast.service' version '0.0.1' was satisfied by service with filter '(&(objectClass=javax.persistence.EntityManagerFactory)(com.springsource.server.app.name=org.opentoast.par-0.0.1))'.
[2009-05-04 19:19:12.837] server-dm-11              Reference '&memberRepository' in bundle 'org.opentoast.par-0.0.1-org.opentoast.service' version '0.0.1' was satisfied by service with filter '(&(objectClass=org.opentoast.domain.MemberRepository)(com.springsource.server.app.name=org.opentoast.par-0.0.1))'.
[2009-05-04 19:19:13.040] async-delivery-thread-1   Starting web application '/opentoast'.
[2009-05-04 19:19:13.769] nection(2)-192.168.0.100  Deployment of 'org.opentoast.par' version '0.0.1' completed.
If you open browser at http://localhost:8080/opentoast/home.htm, it will display current memebrs.

If you run mvn package, it will build final par file at org.opentoast.par/target/OpenToast.par. You can drop it under dm server pickup folder and start the server in command line. Of course, you have to add dependencies into springsource-dm-server-1.0.2.RELEASE\repository\bundles\usr folder before starting.

Wednesday, March 25, 2009

Simple Web Application with SpringSource dm Server (Updated)

I posted my experience of developing web application on SpringSource dm Server, then struggled with Maven, OSGi for last several weeks, didn't know some people asked me questions about the Simple Web Application with SpringSource dm Server. I apologize for not setting comment notification.

So here is the updated tutorial:

1. Download and install Eclipse Ganymede SR2. Install Spring IDE 2.2.2 and dm Server Tools 1.1.2 from http://www.springsource.org/update/e3.4. Download and unzip SpringSource dm Server 1.0.2.RELEASE, and set up a server runtime in Eclipse at localhost.

2. Create a new SpringSource dm Server Bundle Project in Eclipse. Project name is "org.simple.web". Set Java source folder to src/main/java. Next, set symbolic name same as project name, the module type is "Web", and set target runtime to SpringSource dm Server. Next, web context path is "simple", and dispatcher servlet url pattern is "*.htm".

3. After project creation, move the META-INF folder from src/main/java to src/main/resources folder and add the resources folder to Java build source path in Eclipse.

Update the MANIFEST.MF :

Manifest-Version: 1.0
Bundle-Version: 1.0.0
Bundle-Name: Simple Web Bundle
Bundle-ManifestVersion: 2
Bundle-Description: A very simple Spring DM Web Bundle
Bundle-SymbolicName: org.simple.web
Import-Bundle: com.springsource.javax.servlet
 ,com.springsource.javax.servlet.jsp
 ,com.springsource.org.apache.taglibs.standard
 ,org.springframework.core
 ,org.springframework.beans
 ,org.springframework.context
 ,org.springframework.context.support
 ,org.springframework.web
 ,org.springframework.web.servlet
Module-Type: Web
Web-ContextPath: simple
Web-DispatcherServletUrlPatterns: *.htm

The SpringSource dm Server Tool automatically sets up Bundle Dependencies.

4. Add spring config files. Create folder src/main/resources/META-INF/spring, and add module-context.xml, osgi-context.xml.

src/main/resources/META-INF/spring/module-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 <context:component-scan base-package="org.simple.web"/>

 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/"
   p:suffix=".jsp"/>

</beans>

src/main/resources/META-INF/spring/osgi-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
   xmlns="http://www.springframework.org/schema/osgi"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:beans="http://www.springframework.org/schema/beans"
   xsi:schemaLocation="http://www.springframework.org/schema/osgi  
       http://www.springframework.org/schema/osgi/spring-osgi.xsd
       http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans:beans>

5. Create folder "src/main/resources/MODULE-INF", this is the folder for all the web content. Add index.html to MODULE-INF folder:

src/main/resources/MODULE-INF/index.html

<html>
<head>
  <meta http-equiv="Refresh" content="0; URL=home.htm">
</head>
</html>

The index.html redirects to home page "home.htm", and invoke Spring MVC code.

6. Add a very simple jsp file for the home page, just display welcome messag and list all members from backend:

src/main/resources/MODULE-INF/WEB-INF/jsp/home.jsp

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
 <head><title>Open Toast</title></head>
 
 <body>
  <h2>Welcome to Open Toast Project</h2>
  
  <h3>Current Members:</h3>
  <ul>
  <c:forEach items="${members}" var="member">
  <li><c:out value="${member.name}"/>
  </li>
  </c:forEach>
  </ul>
 </body>
</html>

7. Add Spring MVC controller class and support class for home page:

src/main/java/org/simple/web/HomePageController.java

package org.simple.web;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/home.htm")
public class HomePageController {
    public HomePageController() {
    }

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        List<Member> members = new ArrayList<Member>();
        members.add(new Member("Yuan Ji"));
        return new ModelAndView("home", "members", members);
    }
}

src/main/java/org/simple/web/Member.java

package org.simple.web;

public class Member {
    private String name;

    public Member(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

8. Add org.simple.web project to SpringSource dm Server, and start the server. Open browser to http://localhost:8080 and click admin console. click /simple, you can see the home page of Open Toast Project.

Tuesday, January 13, 2009

Add Maven Support to dm Server Bundle Project

It took me several weekends to get maven working with my simple Web application.

My first approach was to use Apache Maven Eclipse Plugin, and add some tricks to work around its limitations. See my comments in Spring Forum dm Server Tooling and Maven: is it possible?

The issue is Maven Eclipse Plugin has not considered dm Server facet settings yet, so you have to manually add WTP project facet setting for dm Server in .settings\org.eclipse.wst.common.project.facet.core.xml file. There maybe some other ways to work around, but not neat.

Then I was thinking about extending its Mojo class org.apache.maven.plugin.eclipse.EclipsePlugin, and by adding additional project natures, build commands, etc. and we were done, just like M2EclipseMojo does. Although hadn't programmed Maven Plugin before, by reading tutorial and source code of Maven Eclipse Plugin, I thought it should be easy.

Setting up a plugin project is easy by following the Plugin Developer's document. Then I spent a whole morning struggling with NPE. First subclassed EclipsePlugin in my plugin project as S2DMEclipseMojo, and in the mojo, added dm Server related config for eclipse, similar to M2EclipseMojo. Theoretically it should work. But the project injected to the plugin was always null.

Tried all kinds of ways to figure out what's wrong, but no clue. Then started to search around in the Internet. Suddenly found this JIRA issue of Maven MPLUGIN-56 Inter-plugin Mojo inheritance. Hmm, Plexus should use JDK 5 annotation instead of javadoc annotation.

Anyway, the problem was found, so the dumb solution was to create a mojo class by copying code from EclipsePlugin and its superclass. After many tests and reviews, I found quite a lot of code is dealing with dependencies. Since we already use dm Server Tool to handle bundle dependency through MANIFEST.MF file, and we can use M2Eclipse plugin in Eclipse to handle unit test related dependencies like junit, easy mock, why not remove all those messy code? So a very simple mojo class was done and tested, seems it meets our needs. See the source code for S2DMEclipseMojo

This is my first Maven Plugin Project, very exciting. Then spent another weekend to get it released as 0.0.1, add documentation, publish to Google Code. It is very nice that we can use Google Code SVN service to publish our Web site and maven repository. See Open Toast Maven Plugin for SpringSource dm Server v0.0.1. The trick is you have to add svn property for all html files as "text/html" mime type. Maybe there is a easy way to do that, I don't know.

To use this plugin is very easy, simply by adding plugin repository in your project pom.xml, like:

 
  
  
   opentoast.maven.s2dm.plugin
   http://opentoastproject.googlecode.com/svn/mavenrepo
  
 

and then in your project root, type

mvn org.opentoast:maven-s2dm-plugin:0.0.1:eclipse

It will add Eclipse settings for the project, so you can import into Eclipse. Suppose you already set up your Eclipse with M2Eclipse and dm Server Tool plugins. You may have to run "Spring Tools - Refresh Bundle Dependencies" to get rid of compiler errors.

To use dm Server Tool with M2Eclipse, I apply another trick learned from Spring forum, that put all bundle dependencies to a profile, so M2Eclipse Plugin cannot find them.

The complete pom for my simple Web application is like this:



 4.0.0

 org.simple
 org.simple.web
 jar
 Simple Web Bundle
 0.0.1-SNAPSHOT

 
  
  3.2.2
  2.5.6.A
  1.1.2.A
  1.0.1
  1.5.0
  2.5.0
  2.1.0
  1.1.2
  4.5.0
  2.3.0
 

 
  
   bundle

   

    
    
     org.springframework
     org.springframework.beans
     
     ${spring.version}
     provided
    
    
     org.springframework
     org.springframework.core
     
     ${spring.version}
     provided
    
    
     org.springframework
     org.springframework.context
     
     ${spring.version}
     provided
    
    
     org.springframework
     org.springframework.context.support
     
     ${spring.version}
     provided
    
    
     org.springframework
     org.springframework.web
     
     ${spring.version}
     provided
    
    
     org.springframework
     org.springframework.web.servlet
     
     ${spring.version}
     provided
    

    
     javax.servlet
     com.springsource.javax.servlet
     
     ${servlet.version}
     provided
    

    
     javax.servlet
     com.springsource.javax.servlet.jsp
     
     ${jsp.version}
     provided
    

    
     org.apache.taglibs
     com.springsource.org.apache.taglibs.standard
     
     ${jstl.version}
     provided
    
   
  
 

 
   
   
    org.easymock
    com.springsource.org.easymock
    ${easymock.version}
    test
   
   
    org.junit
    com.springsource.org.junit
    ${junit.version}
    test
   

   
    org.springframework
    org.springframework.test
    ${spring.version}
    test
   
 
 
 
  
   
   
    org.apache.maven.plugins
    maven-compiler-plugin
    
     1.6
     1.6
    
   

   
    org.apache.maven.plugins
    maven-jar-plugin
    
     
      src/main/resources/META-INF/MANIFEST.MF
      
     
    
   

  
 
 
 
  
  
   opentoast.maven.s2dm.plugin
   http://opentoastproject.googlecode.com/svn/mavenrepo
  
 
 
 
    
   com.springsource.repository.bundles.release
   SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases
   http://repository.springsource.com/maven/bundles/release
  
  
   com.springsource.repository.bundles.external
   SpringSource Enterprise Bundle Repository - External Bundle Releases
   http://repository.springsource.com/maven/bundles/external
  
  
 

See my post Simple Web Application with SpringSource dm Server for other details.

Next step is to focus on Open Toast Project again, and get the whole system running. One goal of open toast project is to set up infrastructure so I can work on business later or easily create new projects. However, it is too long to get infrastructure done, especially when using cutting edge technologies. But isn't it fun?