Archive

Archive for the ‘Maven’ Category

Spring MVC with Sitemesh 3

July 11, 2013 3 comments

In one of my earlier posts I showed some steps to create a project with Struts Tiles. This post mentions the steps to get a basic Spring MVC project running with Sitemesh 3. Sitemesh is a decorator framework. More information on Sitemesh 3 can be found here.

CREATING A BASIC SPRING MVC PROJECT

We will use the Spring Developer Toolsuite and Maven 3 for our project. Go to the toolsuite workspace and select File>New>Spring Template Project and choose Spring MVC Project from the list. Click yes on the download prompt. We will name the project as Sitemesh-SpringMVC and the package as com.wordpress.codesilo.

SETTING UP SITEMESH 3

Open the pom.xml of the Project and add the following dependency.

<dependency>
 <groupId>org.sitemesh</groupId>
 <artifactId>sitemesh</artifactId>
 <version>${sitemesh.version}</version>
</dependency>

Also add the following under properties

<sitemesh.version>3.0-alpha-2</sitemesh.version>

To the web.xml add the following

<filter>
 <filter-name>sitemesh</filter-name>
 <filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>sitemesh</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

Now create a sitemesh3.xml file in the web-inf folder of the project and add the decorator files mapping in the file like follows. We will create the decorator files next.

<sitemesh>
 <mapping path="/*" decorator="/WEB-INF/decorators/defaultDecorator.jsp"/>
 <mapping path="/user" decorator="/WEB-INF/decorators/userDecorator.jsp"/>
</sitemesh>

Create the decorators folder in your project and add the following  jsp files.

defaultDecorator.jsp

<html>
 <head>
 <title><sitemesh:write property='title'/></title>
 <sitemesh:write property='head'/>
 </head>

 <body>
 This is the default body in decorator:
 <sitemesh:write property='body'/>
 </body>
</html>

userDecorator.jsp

<html>
 <head>
 <title><sitemesh:write property='title'/></title>
 <sitemesh:write property='head'/>
 </head>

 <body>
 This is the decorator body in user:
 <sitemesh:write property='body'/>
 </body>
</html>

For the default decorator example we will use the home.jsp that was created as a part of the project template. For the user decorator, we will create a new view in the views folder. We will keep it very simple as follows.

user.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
 <title>User</title>
</head>
<body>
<h1>
 Hello User!
</h1>

<P> Welcome user ! </P>
</body>
</html>

We will also change the HomeController (created again as a part of the template) to add another method for the user request mapping. We will copy the method for the default request mapping and change it as follows. (Add the following code to the HomeConrtoller)

@RequestMapping(value = "/user", method = RequestMethod.GET)
public String user(Locale locale, Model model) {
 logger.info("Welcome home! The client locale is {}.", locale);
 return "user";
}

Now, if we run the application and try the following urls we will see the different results. Notice the content added by the decorators.

http://localhost:8080/codesilo/

SitemeshImage1

http://localhost:8080/codesilo/user

SitemeshImage2

ADDING POST TO SITEMESH3

I read somewhere that Sitemesh 3 had a bug that did not allow it to use POST on the requests. I tried to give it a shot. We will add a field on the default view to accept a name. We will send that as a POST to the user method and display that on the user view.

Here is User.java class.

package com.wordpress.codesilo;

public class User {

private String name;

public String getName() {
 return name;
 }

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

}

The HomeController now looks like this:

 @RequestMapping(value = "/", method = RequestMethod.GET)
 public ModelAndView home(Locale locale, Model model) {
 logger.info("Welcome home! The client locale is {}.", locale);

 Date date = new Date();
 DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

 String formattedDate = dateFormat.format(date);

 model.addAttribute("serverTime", formattedDate );

 return new ModelAndView("home", "command", new User());
 }

 @RequestMapping(value = "/user", method = RequestMethod.POST)
 public String user(Locale locale, @ModelAttribute("SpringWeb")User user, Model model) {
 logger.info("Welcome " + user.getName());
 model.addAttribute(user);
 return "user";
 }

We will change the home.jsp to

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ page session="false" %>
<html>
<head>
 <title>Home</title>
</head>
<body>
<h1>
 Hello world!
</h1>

<P> The time on the server is ${serverTime}. </P>

<form:form method="POST" action="/codesilo/user">
 <form:input path="name" />
 <input type="submit" value="submit"/>
</form:form>

</body>
</html>

And, change user.jsp to

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
 <title>User</title>
</head>
<body>
<h1>
 Hello User!
</h1>

<P> Welcome ${user.name} ! </P>
</body>
</html>

Now if we call the urls we will see this..

http://localhost:8080/codesilo/

SitemeshImage3

Once we hit submit we will get the following

SitemeshImage4

It seems that the POST works too. Maybe it’s some specific case that I have not run into yet.

 

MongoDB Spring Data and Spring Security with custom UserDetailsService

July 8, 2012 12 comments

In a earlier write up we saw how we can setup basic spring security. In this one we will see how to make a custom UserDetailsService instead of using the credentials in the configuration file. We will use MongoDB as a datasource.

We will use the project from the Spring Security project we created earlier and add the MongoDB config details and user service to provide the capability. See my previous blog for setting up MongoDB Spring Data.

Add the following to the mongo-config.xml file in the location WEB-INF/mongo/

<?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:context="http://www.springframework.org/schema/context"
 xmlns:mongo="http://www.springframework.org/schema/data/mongo"
 xsi:schemaLocation="http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.1.xsd
 http://www.springframework.org/schema/data/mongo
 http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

 <!-- Default bean name is 'mongo' -->
 <mongo:mongo host="localhost" port="27017" />

 <bean id="mongoTemplate"
 class="org.springframework.data.mongodb.core.MongoTemplate">
 <constructor-arg ref="mongo" />
 <constructor-arg name="databaseName" value="codesilo" />

 </bean>

 <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
 <context:annotation-config />

</beans>

Add the Spring Data dependencies in the pom.xml file

<dependency>
 <groupId>org.mongodb</groupId>
 <artifactId>mongo-java-driver</artifactId>
 <version>2.7.2</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
 <version>1.1.0.M1</version>
 </dependency>
 <dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib</artifactId>
 <version>2.2</version>
 </dependency>

Add the mongo-config.xml file to the contextConfigLocation on web.xml. The context param will look like this

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/spring/root-context.xml
 /WEB-INF/spring/security-app-context.xml
 /WEB-INF/mongo/mongo-config.xml
 </param-value>
 </context-param>

We will now create a CustomUserDetailsService class that implements UserDetailsService. We will add the implementation of loadUserByUsername method. The CustomUserDetailsService is as follows. The getUserDetail method queries to get the user object from MongoDB (it is assumed that the data is already there).

package com.wordpress.codesilo.model;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class CustomUserDetailsService implements UserDetailsService {

private MongoTemplate mongoTemplate;

 public UserDetails loadUserByUsername(String username)
 throws UsernameNotFoundException {
 User user = getUserDetail(username);
 System.out.println(username);
 org.springframework.security.core.userdetails.User userDetail = new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),true,true,true,true,getAuthorities(user.getRole()));
 return userDetail;
 }

@Autowired
 public void setMongoTemplate(MongoTemplate mongoTemplate) {
 this.mongoTemplate = mongoTemplate;
 }

 public List<GrantedAuthority> getAuthorities(Integer role) {
 List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
 if (role.intValue() == 1) {
 authList.add(new SimpleGrantedAuthority("ROLE_USER"));
 authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
 } else if (role.intValue() == 2) {
 authList.add(new SimpleGrantedAuthority("ROLE_USER"));
 }
 return authList;
 }

 public User getUserDetail(String username){
 MongoOperations mongoOperation = (MongoOperations)mongoTemplate;
 User user = mongoOperation.findOne(
 new Query(Criteria.where("username").is(username)),
 User.class);
 System.out.println(user.toString());
 return user;
 }

}

We will also create a user POJO which is as follows.

package com.wordpress.codesilo.model;

public class User {

public String username;
 public String password;
 public String firstName;
 public String lastName;
 public String email;
 public int role;

public User() {
 }

public int getRole() {
 return role;
 }

public void setRole(int role) {
 this.role = role;
 }

public User(String username, String password, String firstName,
 String lastName) {
 this.username = username;
 this.password = password;
 this.firstName = firstName;
 this.lastName = lastName;
 }

public String getUsername() {
 return username;
 }

public void setUsername(String username) {
 this.username = username;
 }

public String getPassword() {
 return password;
 }

public void setPassword(String password) {
 this.password = password;
 }

public String getFirstName() {
 return firstName;
 }

public void setFirstName(String firstName) {
 this.firstName = firstName;
 }

public String getLastName() {
 return lastName;
 }

public void setLastName(String lastName) {
 this.lastName = lastName;
 }

public String getEmail() {
 return email;
 }

public void setEmail(String email) {
 this.email = email;
 }

@Override
 public String toString(){
 return "First Name:" + this.firstName + " Last Name:" + this.lastName + " Username:" + this.username ;
 }

}

As a last step we will change the security-app-context.xml to have the customUserDetailsService bean and user-service-ref in the authentication provider.

<beans:bean id="customUserDetailsService" class="com.wordpress.codesilo.model.CustomUserDetailsService"/>

 <authentication-manager>
 <authentication-provider user-service-ref="customUserDetailsService"/>
 </authentication-manager>

Now when we try to login to the application it will use the MongoDB to get the credentials.

We can also use the Security Context to get the principal and display the username and roles on home.jsp.
Add this to the pom dependencies.

<dependency>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-taglibs</artifactId>
 <version>${org.springframework-version}</version>
 </dependency>

Add the following taglib to the home.jsp page

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

and the following content on the jsp page to display the data.

<sec:authorize access="isAuthenticated()">
 Username: <sec:authentication property="principal.username" />
 Role: <sec:authentication property="principal.authorities"/>
 </sec:authorize>

Other Notes from migration to Spring 3

April 4, 2011 Leave a comment

Read my previous blog to see why I got here…

Here are some other things I tripped over when moving the project to Spring 3.0

If your project gets the following exception ..

java.lang.ClassNotFoundException: org.springframework.web.struts.ContextLoaderPlugIn

.. you are probably using Struts 1.1 and not including the struts dependency from Spring.
Include this in your maven dependencies and you should be good to go.

<dependency>
  <groupid>org.springframework</groupid>
  <artifactid>spring-struts</artifactid>
  <version>3.0.0.RELEASE</version>
</dependency>

Struts 1.1 dependency was removed in Spring 3.0 but was reintroduced later in deprecated form. Read more about it here.

If your project get the following exception…

java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderServlet

… you were using Spring 2.3 or lower according to this entry.

 

Use ContextLoaderListener instead of ContextLoaderServlet.

Remove the servlet entry from your web.xml for ContextLoaderServlet and add the following listener…

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

Maven dependency tree

April 4, 2011 Leave a comment

I was recently moving our project from Spring 2.5.6 to Spring 3.0 when I encountered a ClassNotFoundException. The jar containing the class was present in the war and everything pointed to a jar conflict.
I tried to search in Eclipse but could not find any reference to any other version of Spring. The following command made my life easy …

mvn dependency:tree -Dverbose

Details can be found here .

It gave me a list of the dependencies in a nice tree format and the culprit was found. It was Spring 2.0.7 jar that was being loaded from a module that I had not imported in Eclipse.

[INFO] |  |  +- com.ostermiller:ostermillerutils:jar:20041102:compile
[INFO] |  |  +- (log4j:log4j:jar:1.2.13:compile - omitted for duplicate)
[INFO] |  |  +- (commons-collections:commons-collections:jar:3.2:compile - omitted for duplicate)
[INFO] |  |  +- <strong>org.springframework:spring:jar:2.0.7:compile</strong>
[INFO] |  |  |  \- (commons-logging:commons-logging:jar:1.1:compile - omitted for conflict with 1.0.4)
[INFO] |  |  +- (org.hibernate:hibernate:jar:3.2.1.ga:compile - omitted for conflict with 3.2.6.ga)
[INFO] |  |  \- net.sourceforge.jtds:jtds:jar:1.2:runtime
[INFO] |  +- (log4j:log4j:jar:1.2.13:compile - omitted for duplicate)

Hope this helps someone who runs into a similar problem.

Technorati Tags: , , , , ,

Categories: Eclipse, Java, Maven, Spring

Basic Spring Code with Maven

May 10, 2010 1 comment

This blog shows how we can use a simple maven project and work with Spring to interact with a database.
First, we create a simple project using the maven command..

mvn archetype:generate

We select the maven-archetype-quickstart project (option 15)
Run the command

mvn eclipse:m2eclipse

to create the .classpath and .project files for eclipse.
We will create a file beans.xml in src/main/resources dir. Not creating the beans.xml file in the resources dir will give you the following exception:
Exception in thread “main” org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [beans.xml]; nested exception is java.io.FileNotFoundException: class path resource [beans.xml] cannot be opened because it does not exist

Here is my beans.xml file.

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

 <bean id="dataSource">
 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
 <property name="url" value="jdbc:mysql://localhost:3306/database-name"></property>
 <property name="username" value="root"></property>
 <property name="password" value="root"></property>
 </bean>
 <bean id="template">
 <property name="dataSource" ref="dataSource"></property>
 </bean>
 <bean id="mySQLDao">
 <property name="template" ref="template"></property>
 </bean>
</beans>

Create a main class with the following code:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
MySQLDao mySQLDao = (MySQLDao)context.getBean("mySQLDao");
System.out.println(mySQLDao.queryForDate());

In MySQLDao we have the following code:

 private JdbcTemplate template;

 public Date queryForDate(){
 String sql = "select now() from dual;";
 Date currentDate = (Date)template.queryForObject(sql, Date.class);
 return currentDate;
 }

 public void setTemplate(JdbcTemplate template) {
 this.template = template;
 }

In pom.xml add the following dependencies:

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-jdbc</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>2.5.6</version>
 <scope>compile</scope>
 </dependency>
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>5.1.11</version>
 <scope>compile</scope>
 </dependency>



If the mysql-connector jar is not installed in the local repository , use the following command to install the jar.

mvn install:install-file -DgroupId=mysql -DartifactId=mysql-connector-java -Dversion=5.1.11 -Dfile=mysql-connector-java-5.1.11-bin.jar -DgeneratePom=true -Dpackaging=jar

Running the main class should now give the current timestamp from the database.
To run main from the command line use the following command

mvn exec:java -Dexec.mainClass="com.wordpress.codesilo.Main"

Accessing databases using datasource xml

March 15, 2010 Leave a comment

We will use the previous struts project to setup database access to MySQL running on localhost.
Run the following command to create the .project and .classpath files for Eclipse and import the project in Eclipse

mvn eclipse:m2eclipse

Download the database driver mysql-connector-java-5.1.11-bin.jar from here and save it to the lib folder in this location $JBOSS_HOME/server/web/lib

Create a jboss-web.xml file in the WEB-INF folder with the following content

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
 <resource-ref>
 <res-ref-name>CodesiloDS</res-ref-name>
 <res-type>javax.sql.DataSource</res-type>
 <jndi-name>java:CodesiloDS</jndi-name>
 </resource-ref>
</jboss-web>

In the web.xml file add the following :

 <resource-ref>
 <res-ref-name>CodesiloDS</res-ref-name>
 <res-type>javax.sql.DataSource</res-type>
 <res-auth>Container</res-auth>
 </resource-ref>

Create a datasource xml file and add it to the deploy dir of JBoss.

Here is the content of my file:

<datasources>
 <local-tx-datasource>
 <jndi-name>CodesiloDS</jndi-name>
 <connection-url>jdbc:mysql://localhost:3306/database-name</connection-url>
 <driver-class>com.mysql.jdbc.Driver</driver-class>
 <user-name>username</user-name>
 <password>password</password>
 <min-pool-size>5</min-pool-size>
 <max-pool-size>20</max-pool-size>
 <!-- Typemapping for JBoss 4.0 -->
 <metadata>
 <type-mapping>mySQL</type-mapping>
 </metadata>
 </local-tx-datasource>
</datasources>

Replace database-name, username and password with appropriate values.

To keep things simple to test, we will add an action in struts-config and have the Action class call the database.

In the action class add this

private final String DATABASE_JNDI_SOURCE = "java:CodesiloDS";

and have this in the execute method. (In the real world most of this code would reside in your model and any helper classes.)

public ActionForward execute(ActionMapping mapping, ActionForm form,
 HttpServletRequest request, HttpServletResponse response)
 throws Exception {

 Connection conn = null;
 Statement stmt = null;
 ResultSet rs = null;
 String date ="";
 try{
 Context ctx = new InitialContext();
 DataSource ds = (DataSource)ctx.lookup(DATABASE_JNDI_SOURCE);
 if(ds!= null){
 conn = ds.getConnection();
 stmt = conn.createStatement();
 rs = stmt.executeQuery("select curdate() from dual;");
 if(rs.next()){
 date = rs.getString(1);
 }
 }
 }
 catch(Exception e){
 ---- code here----
 }
 finally{
 try{
 rs.close();
 stmt.close();
 conn.close();
 }
 catch(Exception e){
 ---- code here -----
 }
 }
 System.out.println("This is a test: " + date);
 return mapping.findForward("success");
 }

Once we call the action, we should see the current date printed on the console.

Maven and Struts 1

February 10, 2010 7 comments

Maven archetype can be used to generate blank projects. However, the mvn archetype:generate command does not give an option to generate an empty struts project with Struts 1. To generate a Struts 1.x project we need to install the struts blank archetype. Use the following commands to download and install struts blank archetype in the local repository.

svn co http://svn.apache.org/repos/asf/struts/maven/trunk/struts-archetype-blank
cd struts-archetype-blank
mvn install

Now to generate a project use the following command

mvn archetype:generate -DarchetypeGroupId=org.apache.struts -DarchetypeArtifactId=struts-archetype-blank -DarchetypeVersion=1.3.5-SNAPSHOT -DgroupId=com.wordpress.codesilo -DpackageName=com.wordpress.codesilo -DartifactId=test-struts

Now we will test this on JBoss AS. Set a variable JBOSS_HOME in bash_profile and change the plugins section generated in the pom.xml file above to the following.

 <plugins>
 <plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>jboss-maven-plugin</artifactId>
 <version>1.4</version>
 <configuration>
 <jbossHome>/${JBOSS_HOME}</jbossHome>
 <serverName>web</serverName>
 <fileName>target/test-struts.war</fileName>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <configuration>
 <source>1.5</source>
 <target>1.5</target>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-war-plugin</artifactId>
 <configuration>
 <webResources>
 <webResource>
 <directory>
 ${basedir}/src/main/webapp/WEB-INF</directory>
 <includes>
 <include>web.xml</include>
 </includes>
 <targetPath>WEB-INF</targetPath>
 <filtering>true</filtering>
 </webResource>
 </webResources>
 </configuration>
 </plugin>
 </plugins>

Now we will use the maven JBoss plugin to deploy the war generated above. Use the following command to deploy the war file.

mvn jboss:hard-deploy

(To undeploy use the command mvn jboss:hard-undeploy)

The war will be deployed to the following dir ($JBOSS_HOME/server/web/deploy) (in JBoss 5). If Jboss 4 is used, change the serverName above to “default”.

On starting Jboss we will see an exception ….
java.lang.ClassCastException: org.apache.xerces.jaxp.SAXParserFactoryImpl cannot be cast to javax.xml.parsers.SAXParserFactory
This can be corrected by removing the jar that is included by the struts-archetype-blank plugin.
Change the following in the pom.xml

 <dependency>
 <groupId>org.apache.struts</groupId>
 <artifactId>struts-core</artifactId>
 <version>1.3.5</version>
 </dependency>

to

 <dependency>
 <groupId>org.apache.struts</groupId>
 <artifactId>struts-core</artifactId>
 <version>1.3.5</version>
 <exclusions>
 <exclusion>
 <groupId>xml-apis</groupId>
 <artifactId>xml-apis</artifactId>
 </exclusion>
 </exclusions>
 </dependency>

The server will now start without any exceptions.