Tuesday, June 17, 2008

Simple Spring Web Flow 2.0 Example Ready

I finally have a very Simple Spring Web Flow 2.0 example ready. It's building on the Spring MVC annotation-based Controller and Spring Security 2.0 examples I did recently. I'm actually still working on a more advanced example showing how to have a subflow for Person addresses, but I wanted to post what was working so far and it might be less confusing to people as they're getting started since there is less going on.

There is an error currently when leaving the flow from a save and a cancel. It says 'Could not complete request' and is an IllegalStateException. It seems to be some problem with a redirect, but everything works fine.

The more advanced subflow example just needs to have messages and validation added to it., and I might try to switch it from using a Hibernate DAO class to using Spring Web Flow's built in JPA persistence hooks. It really took a long time to get the subflow working. I had to try a lot of different things to get the address id passed into the subflow. Spring Web Flow is really nice, but there could be a lot more documentation and examples illustrating things like this. I couldn't find any concrete examples doing this for Spring Web Flow 2.0.




The person flow uses Spring Security to limit the flow to a 'ROLE_USER'. Based on whether or not an id attribute is available, the decision-state element will forward to a 'createPerson' or 'editPerson' action-state. The 'createPerson' one uses El to create a new Person instance for the form to bind to using a method on the person controller. The edit uses the person DAO instance to look up the person record. They both forward to the 'personForm' where you can save or cancel, and save uses the person DAO to save the person instance. The person instance is automatically bound by specifying the model attribute as 'person' on the view-state. Both cancel and save then populate the latest search results and forward to the search page.

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

    <secured attributes="ROLE_USER" />

    <input name="id" />

    <decision-state id="createOrEdit">
        <if test="id == null" then="createPerson" else="editPerson" />
    </decision-state>

    <action-state id="createPerson">
        <evaluate expression="personController.newPerson()"
                  result="flowScope.person" />
        <transition to="personForm" />
    </action-state>

    <action-state id="editPerson">
        <evaluate expression="personDao.findPersonById(id)"
            result="flowScope.person" />
        <transition to="personForm" />
    </action-state>

    <view-state id="personForm" model="person" view="/person/form">
        <transition on="save" to="savePerson">
            <evaluate expression="personDao.save(person)" />

            <evaluate expression="personDao.findPersons()"
                      result="flowScope.persons" />
        </transition>
        <transition on="cancel" to="cancelPerson" bind="false">
            <evaluate expression="personDao.findPersons()"
                      result="flowScope.persons" />
        </transition>
    </view-state>

    <end-state id="savePerson" view="/person/search" />

    <end-state id="cancelPerson" view="/person/search" />

</flow>

Monday, June 9, 2008

Using Spring Security to Secure a Webapp

I had to go to a few different places to get all this working, but I have simple security on a webapp that secures the URLs and a method on a DAO interface. Besides securing the delete method in the DAO interface, the link is also hidden from non-admin users. I have this working with JDBC authentication and also with static users defined in the XML (which are commented out, but still in the XML configuration).

Basically you just need to define a security filter, configure Spring Security in an XML file, secure methods either with pointcuts in the XML or with annotations.


Secure DAO Method
Either secure with an annotation-based config, as in the example posted.

<security:global-method-security secured-annotations="enabled" />

/**
  * Deletes person.
  */
@Secured ({"ROLE_ADMIN"})
public void delete(Person person);

Or as a pointcut in the XML configuration.

<security:global-method-security>
     <!-- Any delete method in a class ending in 'Dao' in the 'org.springbyexample.orm.hibernate3.annotation.dao' package. -->
     <security:protect-pointcut
         expression="execution(* org.springbyexample.orm.hibernate3.annotation.dao.*Dao.delete(..))"
        access="ROLE_ADMIN"/>
</security:global-method-security>

In Spring Security Config
<security:authentication-provider>
     <security:jdbc-user-service data-source-ref="dataSource" />
</security:authentication-provider>

SQL Script
Script works for HSQLDB and based on Spring Security Script. The ACL tables aren't defined because they aren't used at all in this example.

SET IGNORECASE TRUE;

CREATE TABLE users (
     username VARCHAR(50) NOT NULL PRIMARY KEY,
     password VARCHAR(50) NOT NULL,
     enabled BIT NOT NULL
);

CREATE TABLE authorities (
     username VARCHAR(50) NOT NULL,
     authority VARCHAR(50) NOT NULL
);
CREATE UNIQUE INDEX ix_auth_username ON authorities (username, authority);

ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users(username);

INSERT INTO users VALUES ('david', 'newyork', true);
INSERT INTO users VALUES ('alex', 'newjersey', true);
INSERT INTO users VALUES ('tim', 'illinois', true);

INSERT INTO authorities VALUES ('david', 'ROLE_USER');
INSERT INTO authorities VALUES ('david', 'ROLE_ADMIN');
INSERT INTO authorities VALUES ('alex', 'ROLE_USER');
INSERT INTO authorities VALUES ('tim', 'ROLE_USER');

Sunday, June 8, 2008

Unit Testing AspectJ Load-time Weaving with Maven


This came up as a question on the Spring forums and I actually spent a bit of time trying to figure out how to get the unit test working properly when I did this originally. To unit test AspectJ Load-time Weaving (LTW), the surefire plugin needs to be configured to take the LTW agent. Which in this example is the Spring Agent. Also, the test needs to be run in it's own JVM so the javaagent argument can be applied.

The dependency on spring-agent can have it's scope set to 'provided'. It isn't needed as part of the build since it's used as a command line argument and Maven still downloads the jar so it can be referenced for the test in the local Maven repository.



Note: The argLine element should all be together on one line, but was separated to display in the blog entry.

<properties>
     <spring.version>2.5.4</spring.version>
</properties>

<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-agent</artifactId>
     <version>${spring.version}</version>
     <scope>provided</scope>
</dependency>

<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-surefire-plugin</artifactId>
     <version>2.4</version>
     <configuration>
          <forkMode>once</forkMode>
         <argLine>
         -javaagent:${settings.localRepository}
         /org/springframework/spring-agent/${spring.version}/
         spring-agent-${spring.version}.jar
         </argLine>
          <useSystemClassloader>true</useSystemClassloader>
     </configuration>
</plugin>

Friday, June 6, 2008

Maven Internationalized Compilation Issue

I've never had this come up before, but as I was working on a security that was using the internationalization (i18n) from the Basic Webapp Internationalization I decided to add actually inserting a UTF-8 Korean name into the database. This ended up revealing a bug in the
Spring by Example JDBC Module. It wasn't correctly setting the encoding type when reading in a script file. This was easy enough to fix and I made a 1.0.2 release with that and a few other changes including better unit testing for UTF-8 scripts.

I had everything working in Eclipse, but I couldn't successfully run the tests from the command line. I spent quite a while on this and finally realized it was the actual compilation step that was causing a problem. It took a long time because debugging in Eclipse, everything was fine.

The solution to the problem was to explicitly add the character encoding type to the Maven compiler plugin. Eclipse was automatically correctly setting the encoding. After doing the internationalization examples, it seems like everything is still stuck the way it was 7-10 years ago for the most part. You would think that everything should default to the way Java stores a java.lang.String (UTF-16).


<plugin>
     <artifactid>maven-compiler-plugin</artifactid>
     <configuration>
         <source>1.5</source>
         <target>1.5</target>
         <encoding>UTF-8</encoding>
     </configuration>
</plugin>

Saturday, May 24, 2008

Simple Form using Spring MVC Annotations

I just posted a new example using Spring 2.5's new MVC annotations. The new annotations seem pretty nice. I'm not always for tightly coupling configuration with annotations, but in this case most controllers normally have a single purpose. Plus, you still have the XML configuration as an option if a looser coupling between controller and mappings is needed.

The webapp has basic create, update, delete, and search functionality for a person form. The form basically just has a hidden id (primary key), first name, and last name fields. The example uses Spring MVC annotations, Tiles 2 with Spring By Example's Dynamic Tiles Spring MVC Module, Hibernate configured with annotations and used in Spring with a Hibernate template, and internationalized messages. So a requested URL will go through a controller if there is a mapping, data may be put in place for the page to render, message resources are also put into scope for the page to render, and finally the Dynamic Tiles view renderer takes the request URL and uses it as the body of a default Tiles template.
The example is released under the Apache 2.0 license.

The @RequestMapping annotation is used to indicate what requests a method should handle and can handle Ant style patterns to match a request (not shown below). The @RequestParam annotation can be used to have a request parameter automatically mapped to a variable in the method signature. Or a class can be specified, like in the save method, and any values from the request that can be bound to an instance of the class will be and that instance will be passed into the method.

The create method shows that an Object returned will automatically put into the model based on the classes' name (Person.class --> 'person').

Excerpt from Controller
@Controller
public class PersonController {

final Logger logger = LoggerFactory.getLogger(PersonController.class);

private static final String FORM_VIEW_KEY = "/form/person";
private static final String SEARCH_VIEW_KEY = "/search/person";
private static final String FORM_MODEL_KEY = "person";
private static final String SEARCH_MODEL_KEY = "persons";

/**
* Creates a person object and forwards to person form.
*/
@RequestMapping(value="/form/person.html")
public Person create() {
return new Person();
}

/**
* Gets a person based on it's id.
*/

@RequestMapping(value="/info/person.html")
public ModelAndView info(@RequestParam("id") Integer id) {
Person result = personDao.findPersonById(id);

return new ModelAndView(FORM_VIEW_KEY,
FORM_MODEL_KEY
,
result
);
}

/**
* Saves a person.
*/

@RequestMapping(value="/save/person.html")
public ModelAndView save(Person person) {
personDao
.save(person);

return new ModelAndView(FORM_VIEW_KEY,
FORM_MODEL_KEY
,
person
);
}

...

/**
* Searches for all persons and returns them in a
* Collection as 'persons' in the
* ModelMap.
*/

@RequestMapping(value="/search/person.html")
public ModelMap search() {
Collection<Person> lResults = personDao.findPersons();

return new ModelMap(SEARCH_MODEL_KEY, lResults);
}

}

JavaOne 2008

JavaOne was interesting this year. It was non-stop from morning until late at night between presentations, meeting people, and parties in the evening. I wish more of the presentations were more technical, but many were to convey new technologies, JSRs, etc. and didn't have time to delve in-depth. Although, spec leads don't always make the best lecturers even though they know the subject well. Two very good speakers were Brian Goetz and Joshua Bloch.

Brian Goetz's presentation of possible new concurrency features in Java 7 was very interesting. A key feature is to allow a large task that can keep being forked to build a work queue and let the VM manage threading and delegating the task to available CPUs. From what he said, this will apparently scale much better than the way things are handled currently on large multi-core systems, which will become more and more prevalent. Built on top of this forking will be ParallelArrays which will allow much better concurrent processing of large arrays by delegating tasks like getting the max value, sums, filtering, etc. to multiple core processors and then processing the results coming back from all the cores.

Joshua Bloch has an update to his Effective Java book adding around 20 more examples. Apparently his example of creating the classic singleton with a private constructor that returns an instance through a method is hackable in some way (he didn't go over the code) and he said the best way to create a singleton is to use an Enum since then the VM will enforce the singleton paradigm for you. Otherwise he covered some interesting tips on more effectively using enums instead of using complicated two dimensional arrays to contain the data. He signed autographs of the new book at the book store a number of times and I believe his book was the top seller at the book store.

Getting to see new technologies was probably the highlight of JavaOne for me. Sentilla has a new wireless sensor device that uses Java ME. They had them setup at the conference to record temperature, CO2 levels, and used an IR sensor to track people coming in and out of conference rooms. I got a dev kit to play with, but I still need to order some sensors for it (comes with a built in accelerometer). The new Java Speech API presentation was really interesting. It looks very easy to use for speech recognition and synthesis. The spec lead from Conversay did a great demo of their implementation for mobile devices. In a completely normal voice he was able to create a reminder. They've apparently worked on this for 3 years and this implementation in just 256K of memory (main engine not in Java). I was also able to attend the JSR-303 Bean Validation presentation. It's nice to finally see that there will be a validation implementation in the Java language for people to leverage. Validation is very often overlooked by developers even thought it's very important, but hopefully this will help make validation much more accesible to the average developer. In the final keynote address with James Gosling, there were a number of interesting things. There was a Java powered car with quite a number of sensors on it. The JMars project uses Java to help correlate all the data we've been receiving from Mars to make it easier to review. It was pretty cool that they showed a satellite image and were able to bring up a rover view of the same spot. Also an arrow pointed between the two images to indicate the rock you saw from orbit was the same one the rover was looking at. Someone from CERN labs was there and apparently almost everything they have is Java powered. Lot's of Swing GUIs and probably one of the cooler things was seeing Java 3D show the result of a collision and all the subatomic particles generated.

It's really amazing what Java is being used for and how much better the performance is compared to 10 years ago. It's also amazing how far Open Source projects have come and their wide acceptance in corporate culture. SpringSource, the developers of the Spring Framework, have become a very large company based their framework. I saw people from SpringSource every night I was out. Oddly there were only 3 Spring presentations at JavaOne (two of new features in Spring 2.5 by Rod Johnson and a Spring Security presentation by Ben Alex). I say oddly because according to SpringSource, Spring has surpassed EJBs as the primary skillset requested on job boards from developers. I felt Sun focused a little too much on it's technologies. It is supposed to be JavaOne, not SunOne. There's nothing wrong with an Open Source project surpassing something in Java EE. In fact I think that this is what gives Java an edge over .NET. Without all the great open source initiatives, it would be a much more level playing field between the two.

I'm glad I was able to attend and hopefully I will be able to attend again next year.
I had time to see Tim O'Brien, author of the Jakarta Commons Cookbook (among others), and current Maven Sage. I also met Emmanuel Bernard, the specification lead for JSR-303, briefly after his presentation. I was able to talk to a few people from SpringSource that I met at The Spring Experience too. I highly recommend going to The Spring Experience if you're using Spring or want to. It looks like Java will be more and more places that you might not expect it over the next year. Hopefully it will be another good year for Java and the language and Open Source projects will continue to evolve to fulfill everyone's needs. I'm happy that I still enjoy programming in it and also to be getting back involved in Open Source.

Spring Hibernate Examples

Before JavaOne I was able to post some Hibernate examples to Spring by Example. They are simple examples showing how to configure Hibernate with XML or annotations and setting them up with a Spring Hibernate template. There is also one example showing how to use transactions and also how to do a transactional JUnit 4 test.