Tag Archives: spring-roo

Say Hello to Jelastic

These days Platform as a Service (PaaS) is one of my interest areas and I like to play with different PaaS providers to see how easy or difficult it is to develop and deploy application on them. The best thing about most of the current new generation PaaS systems is that they don’t require you to change your code or learn new programming paradigm. Google App Engine is thing of past and is losing ground in PaaS race. For last six months I have spend some of my spare time on OpenShift and Cloud Foundry and one thing I can say is that I love both of the platforms. Today I decided to spend some time on Jelastic — seeing how easy or difficult is to deploy a simple Spring MongoDB application on it. According to Jelastic website

Jelastic is the next generation of Java hosting platforms which can run and scale ANY Java application with no code changes required

Jelastic provides a web ui using which you can create the deployment environment and upload your war file to it.To check the usability of the UI I decided that I will not refer to Jelastic documentation and will try to deploy the application based on my understanding. So in this blog I am sharing the steps I performed to deploy a simple Spring MongoDB application to Jelastic.

  1. To start I created a very simple simple moviestore application using Spring Roo. For those of you who are not aware of Spring Roo can refer to my article series at IBM Developerworks on Spring Roo.Once you have installed Spring Roo, fire the Roo shell and execute following commands. This will create a Spring MVC web application with MongoDB as backend.
    project --topLevelPackage com.shekhar.moviestore --projectName moviestore
    mongo setup --databaseName moviestore
    entity mongo --class ~.domain.Movie
    field string --fieldName title --notNull
    field string --fieldName description --notNull
    repository mongo --interface ~.repository.MovieRepository
    service --interface ~.service.MovieService
    web mvc setup
    web mvc all --package ~.web
    q
    
  2. You can test the application locally by first starting the MongoDB server and then starting the application using mvn tomcat:run.
  3. But the point is to test the application on Jelastic. So go to http://jelastic.com/ and sign up for free. You don’t need to pay anything. I choose North America hosting provider.
  4. Once you have registered at Jelastic login with your credentials at https://app.jelastic.servint.net/
  5. After you have logged in to Jelastic portal you will see a Create environment link on the left. In Jelastic you have to first create environment under which your application will run. Click on the environment link and choose MongoDB, Tomcat, Java 6 as the environment topology. This is shown in image below. I really liked the UI. It is sexy.
  6. When you press create it will take couple of minutes to create the environment. So please be patient.
  7.  You will receive an email from Jelastic with the MongoDB connection details. It will give you a url to access MongoDB from web UI and an admin username and password.In my case I received url http://mongodb-moviestore.jelastic.servint.net/. I am not going to share username and password.
  8. The MongoDB UI is a RockMongo MongoDB web client. Login into it using admin username and password and Rock 🙂
  9. Next we need to create a MongoDB database and user with which our application can connect. To create database first click on databases and then “Create new Database”. Enter the name of database as moviestore and press create button. Next click on newly created moviestore database and click more then authentication and then click on add user to create a new user. Create a user with username as moviestore and password as password and press Add user.
  10. Now that we have created a user we should update the database.properties and applicationContext-mongo.xml files which were created by Spring Roo. By default they were pointing to localhost. Update the files as shown below.
    database.properties

    #Updated at Tue Feb 28 12:26:32 IST 2012
    #Tue Feb 28 12:26:32 IST 2012
    mongo.host=mongodb-moviestore.jelastic.servint.net
    mongo.name=moviestore
    mongo.password=password
    mongo.port=27017
    mongo.username=moviestore
    

    applicationContext-mongo.xml

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:cloud="http://schema.cloudfoundry.org/spring" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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        http://schema.cloudfoundry.org/spring http://schema.cloudfoundry.org/spring/cloudfoundry-spring-0.8.xsd">
    
        <mongo:db-factory dbname="${mongo.name}" host="${mongo.host}" id="mongoDbFactory" password="${mongo.password}" port="${mongo.port}" username="${mongo.username}"/>
    
        <mongo:repositories base-package="com.shekhar.moviestore"/>
    
        <!-- To translate any MongoExceptions thrown in @Repository annotated classes -->
        <context:annotation-config/>
    
        <bean class="org.springframework.data.mongodb.core.MongoTemplate" id="mongoTemplate">
            <constructor-arg ref="mongoDbFactory"/>
        </bean>
    
    </beans>
    
  11. Build the maven project by executing mvn clean install command.
  12. Then upload the war by clicking on upload link in the Jelastic web UI.This will take some time depending on your internet connection.
  13. After the war is uploaded you will see the war in deployment manager tab. Click deploy to moviestore environment to deploy to tomcat and select context as ROOT.
  14. Finally you will be able to view the application running at http://moviestore.jelastic.servint.net/

This was my first write up on Jelastic and I will continue experimenting with it and evaluating its capabilities. I will also spend time reading its documentation and see how it compare with other PaaS providers. Overall I was impressed with Jelastic and to me it looks like a good deployment option for Java applications.

Spring Roo PGP Exception

Today when I fired Spring Roo shell I started getting exception as shown below and I was not able to execute any command. I uninstalled Spring Roo (thinking that it might have got corrupted) but it didn’t helped after lot of firefighting I figured out the solution to overcome this problem. The problem was that yesterday I trusted some pgp keys and somehow Roo was not able to find them and started throwing exception. The solution is to remove a file name .spring_roo_pgp.bpg and restart Spring Roo. Spring Roo will create a new clean file. Continue reading

Writing to OpenShift Express File System

One of the features that you will not find in most Platform as a Service solutions is writing to file system. Writing to file system is very important as you need it in case you want to write user uploaded content to file system, or write lucene index or read some configuration file from a directory. OpenShift Express from the start support writing to file system.

In this blog I will create a simple Spring MVC MongoDB application which store movie documents. I will be using Spring Roo to quickly scaffold the application. Spring Roo does not provide file upload functionality so I will modify the default application to add that support. Then I will deploy the application to OpenShift Express.

Creating a OpenShift Express JBoss AS7 application

The first step is to create the JBoss AS7 applictaion in OpenShift Express. To do that type the command as shown below. I am assuming you have OpenShift Express Ruby gem installed on your machine.

rhc-create-app -l <rhlogin email> -a movieshop -t jbossas-7.0 -d

This will create a sample Java web application which you can view at http://movieshop-<namespace&gt;.rhcloud.com.

Adding support for MongoDB Cartridge

As we are creating Spring MongoDB application we should add support for MongoDB by executing the command as shown below.

rhc-ctl-app -l <rhlogin email> -a movieshop -e add-mongodb-2.0 -d

Removing default generated file from git

We don’t need the default generated files so remove them by executing following commands.

git rm -rf src pom.xml
git commit -a -m "removed default generated files"

Creating Spring MVC MongoDB MovieShop Application

Fire the Roo shell and execute the following commands to create the application.

project --topLevelPackage com.xebia.movieshop --projectName movieshop --java 6
mongo setup
entity mongo --class ~.domain.Movie
repository mongo --interface ~.repository.MovieRepository
service --interface ~.service.MovieService
field string --fieldName title --notNull
field string --fieldName description --notNull --sizeMax 4000
field string --fieldName stars --notNull
field string --fieldName director --notNull
web mvc setup
web mvc all --package ~.web

Adding file upload support

Add two fields to Movie entity as shown below.

@Transient
private CommonsMultipartFile file;
private String fileName;

public CommonsMultipartFile getFile() {
    return this.file;
}
public void setFile(CommonsMultipartFile file) {
    this.file = file;
}
public String getFileName() {
   return fileName;
}
public void setFileName(String fileName) {
   this.fileName = fileName;
}

Edit the create.jspx file as shown below to add file upload as shown below.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <form:create id="fc_com_xebia_movieshop_domain_Movie" modelAttribute="movie" path="/movies" render="${empty dependencies}" z="wysyQcUIaJOAUzNYNVt5nMEdvHk=" multipart="true">
        <field:input field="title" id="c_com_xebia_movieshop_domain_Movie_title" required="true" z="SpYrTojoyx2F7X5CjEfFQ6CBdA4="/>
        <field:textarea field="description" id="c_com_xebia_movieshop_domain_Movie_description" required="true" z="vxiB62k7E7FzhnVz1kU7CCIYEkw="/>
        <field:input field="stars" id="c_com_xebia_movieshop_domain_Movie_stars" required="true" z="XdvY0mpBitMGzrARD3TmTxxXZHg="/>
        <field:input field="director" id="c_com_xebia_movieshop_domain_Movie_director" required="true" z="6L8yvzx1cZgTq0QKP1dHbGHbQxI="/>
        <field:input field="file" id="c_com_shekhar_movieshop_domain_Movie_file" label="Upload image" type="file" z="user-managed"/>
        <field:input field="fileName" id="c_com_xebia_movieshop_domain_Movie_fileName" z="user-managed" render="false"/>
    </form:create>
    <form:dependency dependencies="${dependencies}" id="d_com_xebia_movieshop_domain_Movie" render="${not empty dependencies}" z="nyAj+bBGTpzOr2SwafD6lx7vi30="/>
</div>

Also change the input.tagx file to add support for input type file. Add the following line as shown below

<c:when test="${type eq 'file'}">
      <form:input id="_${sec_field}_id" path="${sec_field}" disabled="${disabled}"  type="file"/>
</c:when>

Modify the MovieController to write file either to the OpenShift_DATA_DIR or my local machine in case System.getEnv(“OPENSHIFT_DATA_DIR”) is null. The code is shown below.

import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

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

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.roo.addon.web.mvc.controller.scaffold.RooWebScaffold;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

import com.xebia.movieshop.domain.Movie;
import com.xebia.movieshop.service.MovieService;

@RequestMapping("/movies")
@Controller
@RooWebScaffold(path = "movies", formBackingObject = Movie.class)
public class MovieController {

	private static final String STORAGE_PATH = System.getEnv("OPENSHIFT_DATA_DIR") == null ? "/home/shekhar/tmp/" : System.getEnv("OPENSHIFT_DATA_DIR");

	@Autowired
    MovieService movieService;

	@RequestMapping(method = RequestMethod.POST, produces = "text/html")
	public String create(@Valid Movie movie, BindingResult bindingResult,
			Model uiModel, HttpServletRequest httpServletRequest) {
		if (bindingResult.hasErrors()) {
			populateEditForm(uiModel, movie);
			return "movies/create";
		}
		CommonsMultipartFile multipartFile = movie.getFile();
		String orgName = multipartFile.getOriginalFilename();
		uiModel.asMap().clear();
		System.out.println(orgName);
		String[] split = orgName.split("\\.");
		movie.setFileName(split[0]);
		movie.setFile(null);
		movieService.saveMovie(movie);
		String filePath = STORAGE_PATH + orgName;
		File dest = new File(filePath);

		try {
			multipartFile.transferTo(dest);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return "redirect:/movies/"
				+ encodeUrlPathSegment(movie.getId().toString(),
						httpServletRequest);
	}

	@RequestMapping(value = "/image/{fileName}", method = RequestMethod.GET)
	public void getImage(@PathVariable String fileName, HttpServletRequest req, HttpServletResponse res) throws Exception{
		File file = new File(STORAGE_PATH+fileName+".jpg");
		res.setHeader("Cache-Control", "no-store");
		res.setHeader("Pragma", "no-cache");
		res.setDateHeader("Expires", 0);
		res.setContentType("image/jpg");
		ServletOutputStream ostream = res.getOutputStream();
		IOUtils.copy(new FileInputStream(file), ostream);
		ostream.flush();
		ostream.close();
	}

Also change the show.jspx file to display the image.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:page="urn:jsptagdir:/WEB-INF/tags/form" version="2.0">
    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <page:show id="ps_com_xebia_movieshop_domain_Movie" object="${movie}" path="/movies" z="2GhOPmD72lRGGsTvy9DYx8/b/b4=">
        <field:display field="title" id="s_com_xebia_movieshop_domain_Movie_title" object="${movie}" z="L3rzNq9mt4vOBL/2S9L5XTn4pGA="/>
        <field:display field="description" id="s_com_xebia_movieshop_domain_Movie_description" object="${movie}" z="rctpFQukL584DSNTEhcZ/zqm19U="/>
        <field:display field="stars" id="s_com_xebia_movieshop_domain_Movie_stars" object="${movie}" z="Mi3QNsQkI5hqOVW44XwXAGF2zKE="/>
        <field:display field="director" id="s_com_xebia_movieshop_domain_Movie_director" object="${movie}" z="rhXx3l+3zMxx0O0ht2Td3Icx1ZE="/>
        <field:display field="fileName" id="s_com_xebia_movieshop_domain_Movie_fileName" object="${movie}" z="7XTMedYLsWVvZkq2fKT0EZpZaPE="/>
        <IMG alt="${movie.fileName}" src="/movieshop/movies/image/${movie.fileName}" />
    </page:show>
</div>

Finally change the webmvc-config.xml to have CommonsMultipartResolver bean as shown below.

<bean
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
		id="multipartResolver" >
		<property name="maxUploadSize" value="100000"></property>
	</bean>

Pointing to OpenShift MongoDB datastore

Change the applicationContext-mongo.xml to point to OpenShift MongoDB instance as shown below.

<mongo:db-factory dbname="${mongo.name}" host="${OPENSHIFT_NOSQL_DB_HOST}"
			port="${OPENSHIFT_NOSQL_DB_PORT}" username="${OPENSHIFT_NOSQL_DB_USERNAME}"
			password="${OPENSHIFT_NOSQL_DB_PASSWORD}" />

Add OpenShift Maven Profile

OpenShift applications require maven profile called openshift which is executed when git push is done.

<profiles>
		<profile>
			<!-- When built in OpenShift the 'openshift' profile will be used when
				invoking mvn. -->
			<!-- Use this profile for any OpenShift specific customization your app
				will need. -->
			<!-- By default that is to put the resulting archive into the 'deployments'
				folder. -->
			<!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
			<id>openshift</id>
			<build>
				<finalName>movieshop</finalName>
				<plugins>
					<plugin>
						<artifactId>maven-war-plugin</artifactId>
						<version>2.1.1</version>
						<configuration>
							<outputDirectory>deployments</outputDirectory>
							<warName>ROOT</warName>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>

Deploying Application to OpenShift

finally do git push to deploy the application to OpenShift and you can view the application running at http://movieshop-random.rhcloud.com/

Fixing Exception — Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)

If you are working with Spring Roo and suddenly start getting exception “Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)” then make sure you have _Configurable.aj ITD in your project. This ITD makes the sure that your entity classes have all the required dependencies like EntityManager injected in them. Configurable ITD  looks like as shown below

privileged aspect Movie_Roo_Configurable {

    declare @type: Movie: @Configurable;

}

Spring Roo + OpenShift Express == Extreme Productivity In Cloud Part 1

Today, I released the second version of OpenShift Express Spring Roo Add-on. With this release add-on also support creation of domain namespace and changing the domain namespace. Now the only important thing left in the add-on is support for session management so that users does not  have to enter email and password with every command. From today, I am starting a series of short blog posts which will cover the features of this add-on. In this post I will be  talking about creating and changing domain namespace. Before I get into details lets me first tell you what is Spring Roo and OpenShift Express in case you don’t know about them.

Note :You can also refer to my Spring Roo series on IBM DeveloperWorks for more details.

What is Spring Roo?

Spring Roo is a lightweight productivity tool for Java™ technology that makes it fast and easy to develop Spring-based applications. Applications created using Spring Roo follow Spring best practices and are based on standards such as JPA, Bean Validation (JSR-303), and Dependency Injection (JSR-330). Roo offers a usable, context-aware, tab-completing shell for building applications. Spring Roo is extensible and allows add-ons, enhancing its capability.

What is OpenShift Express?

OpenShift Express is a Platform as a Service offering from RedHat. OpenShift Express allows you to create and deploy applications to the cloud. The OpenShift Express client is a command line tool that allows you to manage your applications in the cloud. It is currently free and runs on Amazon EC2. Currently it supports Java, Ruby, PHP, Python run times. You can refer to OpenShift Express documentation for more details.

OpenShift Express Client Tools

OpenShift Express has three client tools for creating and deploying applications to cloud. These are RHC Ruby Gem., OpenShift Express Eclipse Plugin, and SeamForge RHC Plugin. I have mainly used RHC Ruby Gem and it is very easy to use and work. There were two problems why I decided to write Roo add-on. One is that you need Ruby Runtime and second is I use Spring Roo a lot so it allows me to perform full lifecycle of the application from within Roo shell. Because I am writing add-on I can also do lot of interesting stuff like session management, making some changes to the code to avoid repetitive work. One such thing that I have already added is adding OpenShift profile in the pom.xml. This will help me automate repetitive work.

Lets Get Started

Getting started with the add-on is very easy. First you need to download Spring Roo and fire the Roo shell. Once inside the Roo shell we have to install the add-on. To do this execute the following command as shown below.

osgi start --url http://spring-roo-openshift-express-addon.googlecode.com/files/org.xebia.roo.addon.openshift-0.2.RELEASE.jar

It will take couple of seconds to install the add-on. You can view that a new OSGI process has started using osgi ps command.

Creating Domain

Before you can create domain please signup at https://openshift.redhat.com/app/express.  The email and password with which you signup will be the credentials for accessing the cloud. After you have signed up the next step is to create a domain. You can’t create the applications before creating a domain. The domain is a logical name within which all your applications will reside. It forms the part of your application url. For example if you created a domain with name “paas” and application with name “openshift” your application url will be http://openshift-paas.rhcloud.com . We can create the domain using rhc-create-domain command but in this blog I will show you how to create using Spring Roo add-on. To create domain using Spring Roo execute the command shown below.

rhc create domain --namespace openpaas --rhLogin <rhlogin> --password <password> --passPhrase <passphrase>

This command does the following things :

  1. It will create the ssh keys under user.home/.ssh folder if they does not exist. The passphrase is required for creating the sshkeys.
  2. If ssh keys already exists it loads the ssh keys from user.home/.ssh location and reuse them.
  3. finally it creates the domain with namespace openpaas.
  4. In case your credentials are wrong it will show a log line saying that credentials are wrong.

Changing Domain Namespace

Although you can’t delete a domain after you have created but you can change the domain name. To do that you can use the command shown below.

rhc change domain --namespace xyz --rhLogin <rhlogin> --password <password>

This will change the domain name to xyz.

Thats it for this blog. In the next blog we will look at how to create Spring JPA application using Spring Roo and deploy it to OpenShift Express.

Spring Roo Add-on Release Problems

I am writing a add-on for deploying Spring Roo applications to OpenShift Express cloud just like the Cloud Foundry Spring Roo add-on. The add-on is available at http://code.google.com/p/spring-roo-openshift-express-addon/. But I face problems when I release the add-on using Maven Release plugin (mvn release:prepare release:perform). So, this is simple guide to help me next time I face these issues.

  1. SnapShot Dependencies : The first problem I face is that my add-on depend on OpenShift Java client which is available as Snapshot dependency. So, I need to ignore the snapshot dependencies. This is not recommeded but some times you don’t have any other solution. For more information refer to this post http://stackoverflow.com/questions/245932/how-to-release-a-project-which-depends-on-a-3rd-party-snapshot-project-in-maven
    mvn release:prepare release:perform -DignoreSnapshots=true
    
  2. Adding Third Party Jars in an OSGI bundle. I have blogged this at https://whyjava.wordpress.com/2012/01/02/adding-third-party-jars-to-an-osgi-bundle/.
  3. The third problem I face is that svn client is not able to authenticate with Google Code. The exception that I get is shown below. To fix this I specify username and password with mvn release command as shown below.
    mvn release:prepare release:perform -DignoreSnapshots=true -Dusername=shekhar.xebia@gmail.com -Dpassword=password
    

    The exception that I get is

    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.2:prepare (default-cli) on project org.xebia.roo.addon.openshift: Unable to commit files
    [ERROR] Provider message:
    [ERROR] The svn command failed.
    [ERROR] Command output:
    [ERROR] svn: Commit failed (details follow):
    [ERROR] svn: MKACTIVITY of '/svn/!svn/act/b8000ba7-c3c6-4bb2-9d3b-bd3c1db73dd3': authorization failed: Could not authenticate to server: rejected Basic challenge (https://spring-roo-openshift-express-addon.googlecode.com)
    [ERROR] -> [Help 1]
    [ERROR]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR]
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException