Assignment 2

Deadline Date September 13, 23:59

You must pass this assignment to pass the course. There is no retry for this assignment, so be sure to get it right the first time you deliver. 

Meet up to your lab sessions to ask your group teacher if you have any questions.

 

These are some basic instructions on how to set up your development environment. We strongly recommend using your own laptop, and the prefered operating system for development and running the software is Linux (Ubuntu).


If have to use University computers, some of the below programs are already installed.

From a bare-bone linux Ubuntu, you need to install:

  • Java (already installed on UIO computers)
  • Eclipse (already installed on UIO computers, but we prefer a different version, so we would recommend installing your own version in your home folder)
  • Maven (already installed on UIO computers)

Installation

First create the ~/opt directory if you don’t have it.

$ mkdir ~/opt
$ cd ~/opt

Installing Java (already installed on university computers)

There are several different suppliers of Java. Oracle is one, and OpenJDK is another. You can use either, but these are the instructions for openjdk. Use v7 of JDK in case you run DHIS2 later. Type:
$ sudo apt-get install openjdk-7-jdk


Installing Maven 

Maven is the build system. It helps by downloading the external objects you depend on automatically, but you have to tell it which components your files are dependent on. These dependencies are defined in a file called pom.xml. If maven is not available on the IFI-computer, please download from the maven site and unzip it: 

$ tar xzvf apache-maven-3.3.3-bin.tar.gz

Move the files into ~/opt/mvn.  

$ cd ~/

$ nano .bashrc

Add the following line

export PATH=$PATH:~/opt/mvn/bin

(Save the file. Ctrl+X, then Y and Enter)


Install maven on your computer:

$ sudo apt-get install maven

Check that it installed properly.

$ mvn -version

Installing Eclipse

There is an eclipse installed on university computers, but the version you should use is the JEE-package, which is not installed. So you should follow these instructions to install the appropriate version on your home area. Do not use apt-get to install eclipse. Instead, download the installation file.

Unpack (or use the archive manager if you know how to do that)

$ tar xzvf eclipse-<filename>.tar.gz

Move the files into ~/opt/eclipse.  

Create a symlink on your machine in /usr/bin (not possible in university computers, so you have to add eclipse to your user path)

$ sudo ln -s ~/opt/eclipse/eclipse /usr/bin/eclipse

Run Eclipse from the terminal for the first time (after the first time, you should use: $ eclipse &)

$ eclipse -clean &

Running this command at the university computers is likely to start up the default eclipse, which is not what you want. Instead use the path to your own eclipse. For example:

~/opt/eclipse -clean &

Installing git (already installed on university computers)

You do not need to install git on university computers. For Ubuntu, you can run the following command to install git:

$ sudo apt-get install git

Then run

$ git - version

to check that it’s installed ok.

Spring Framework

Spring is a framework to connect different java objects together into an application. The connections between java objects are managed using XML files or auto-discovery instead of hard-coding connections inside Java classes. This helps create a more configurable and flexible system. You will now create an eclipse project with some simple Spring components, using something called Spring MVC.
Spring documentation

For setting up a Maven project in eclipse (parts of this assignment is based on that web page, but not everything is the same), check out the concept of Archetypes

It is now time to create a directory where you want to keep your Java projects for this course. After crating this directory, continue to create a maven project with with the command "mvn archetype ...". However, instead of ‘assignment2’, please use assignment2_<username>. This will help your group teacher distinguish between the different projects. You do not have to change the package names in the project to include your username (but you must use (assignment2_<username> for your project name/artifactid). This also means you have to change some of the example files in this assignment to include _<username>.

$ mvn archetype:generate -DgroupId=no.uio.inf5750  -DartifactId=assignment2 -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Cd into the assignment2-directory and look at the file structure. Note that you now have a pom.xml, which is the file that tells Maven how to build your project.

Import the maven project into eclipse using the user interface inside Eclipse by using the menu item "File->import->Maven->Existing Maven projects".

If you cannot see the "Import->Maven" selection, you are using an eclipse without the Maven plugin. Check out the top of the assignment. You have either not installed the JEE Eclipse package, or you have several eclipse installations and you are running the wrong one. We recommend using the JEE package with the Maven plugins. 

Select the directory where your pom file is. Select the project in the list, and click Next and Finish. You should now see the project in Eclipse, similar to the diagram below.

If you get build about a servlet library not being available, this should probably not matter at this point. You can remove it a bit later in the assignment after you’ve installed Tomcat, by adding the Tomcat runtime libraries to your project path.

Read web.xml and pom.xml and try to understand it.

Change your pom.xml file to the following. Note which components we are adding.  This is the file that defines the build process, and dependencies. You can see that we are now adding Spring. After editing the pom.xml, select "Run As -> Maven Install" in eclipse to build the project (this may happen automatically depending on your eclipse).

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>no.uio.inf5750</groupId>
  <artifactId>assignment2</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>assignment2 Maven Webapp</name>
  <url>http://maven.apache.org</url>
 
  <properties>
                <spring.version>3.2.3.RELEASE</spring.version>
                <junit.version>4.11</junit.version>
                <jdk.version>1.6</jdk.version>
        </properties>
 
        <dependencies>
 
                <!-- Spring 3 dependencies -->
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-core</artifactId>
                        <version>${spring.version}</version>
                </dependency>
 
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>${spring.version}</version>
                </dependency>
 
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-webmvc</artifactId>
                        <version>${spring.version}</version>
                </dependency>
 
                <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <version>${junit.version}</version>
                        <scope>test</scope>
                </dependency>

                <dependency>
                        <groupId>javax.servlet</groupId>
                        <artifactId>javax.servlet-api</artifactId>
                        <version>3.1.0</version>
                        <scope>provided</scope>
                </dependency>
                
  </dependencies>
 
  <build>
        <finalName>assignment2</finalName>
<!--
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
            </plugin>
        </plugins>
-->
    </build>
</project>

Use the ‘New source folder’ item to create the directory "/src/main/java" if it doesn’t exist already.

Adding a source folder may be a bit tricky if the above gives the error: “the folder is already a source folder”. Then you have to add the folder using "File->New->New Folder", select assignment2 as the project and type "/src/main/java". Further, you may need to manually assign the java folder for the compiler, inside "project properties -> Java Build path" -> "Add folder" (add /src/main/java).

Create a package no.uio.inf5750.assignment2.controller inside that folder. Do this by right-clicking the src/main/java in the project explorer and selecting "New->Package"

The user interface is placed in *.jsp files, while the user interface controller logic is placed in java classes that are annotated using the @Controller annotation. You will now create such a controller.

Create a file BaseController.java inside the controller Java package, with the contents below.

@RequestMapping("/") maps the root url to this method. So for example, the URL to access this method from a web browser could be: http://localhost:8080/assignment2-username/ 

@RequestMapping("/welcome") maps the /welcome url to this method.

/src/main/java/no/uio/inf5750/assignment2/controller/BaseController.java

package no.uio.inf5750.assignment2.controller;

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

 
@Controller
public class BaseController {

        @RequestMapping(value="/", method = RequestMethod.GET)
        public String welcome(ModelMap model) {

                model.addAttribute("message", "Maven Web Project + Spring 3 MVC - welcome()");

                //Spring uses InternalResourceViewResolver and return back index.jsp
                return "index";

        }

        @RequestMapping(value="/welcome/{name}", method = RequestMethod.GET)
        public String welcomeName(@PathVariable String name, ModelMap model) {

                model.addAttribute("message", "Maven Web Project + Spring 3 MVC - " + name);
                return "index";

        }

}

Create a Spring configuration file called mvc-dispatcher-servlet.xml (see below).

Make sure your context:component-scan path in the file matches the name of your package where your controller is. The component-scan is the tag that tells Spring where to looks for classes with annotations such as @Controller in the file above. It will scan sub-directories.
The file below also defines that the JSP files will be in a different sub-directory where they are not directly accessible by a browser. You’ll have to create this folder and put the JSP files there later. There are several alternatives to using Java Server Pages (JSP) to implement the presentation logic. You will also learn about Velocity as a JSP alternative in the course.

/src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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-3.2.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.2.xsd">

        <context:component-scan base-package="no.uio.inf5750.assignment2" />

        <bean
                class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix">
                        <value>/WEB-INF/pages/</value>
                </property>
                <property name="suffix">
                        <value>.jsp</value>
                </property>
        </bean>

</beans>

Update existing web.xml to support Servlet 2.5 (the default Servlet 2.3 is too old), and also integrates Spring framework into this web application project via Spring’s listener ContextLoaderListener. If you get an error “Cannot change version of project facet Dynamic Web Module to 2.5.” then check this solution here.

This is a good time to google or read in your spring-book about the DispatcherServlet.

Note that the location of the above xml-file (mvc-dispatcher-servlet.xml)  is configured into this file.

/src/main/webapp/WEB-INF/web.xml (replace the existing file with this content)

<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>Counter Web Application</display-name>
        <servlet>
                <servlet-name>mvc-dispatcher</servlet-name>
                <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
                <servlet-name>mvc-dispatcher</servlet-name>
                <url-pattern>/</url-pattern>
        </servlet-mapping>
        <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
        </context-param>
        <listener>
                <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <filter>
                <filter-name>encodingFilter</filter-name>
                <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                <init-param>
                        <param-name>encoding</param-name>
                        <param-value>UTF-8</param-value>
                </init-param>
        </filter>
        <filter-mapping>
                <filter-name>encodingFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
 
</web-app>

Move the existing index.jsp inside folder WEB-INF/pages, to protect user access it directly. In additional, edit the file to print out the ${message} variable that is passed by the controller.

/src/main/webapp/WEB-INF/pages/index.jsp

<html>
<body>
<h2>Hello World!</h2>

<h4>Message : ${message}</h4>        
</body>
</html>

Review the final directory structure


Select Run On Server -> Tomcat v7.0

Click Download and install. Create directory ~/opt/tomcat. Check that you get a web page in your web browser. Likely url is something like
http://localhost:8080/assignment2/ 
and
http://localhost:8080/assignment2/welcome/john (the url may be different from assignment2, including _<username> depending on what you’ve called your project)

Now edit the BaseController.java class, adding a new method called helloWorld, which maps to the url “/hello” and takes one url parameter as a input (similar to welcomeName).


Also add an additional JSP-file, called ‘hello.jsp’.


Edit these two files so that the following URL prints “Hello <name> and hello world.”
Now edit index.jsp and hello.jsp so that they have links between them.
If you want to, add your own personal touch to the index.jsp and hello.jsp files. Edit them, create some more @RequestMapping for paths within the same BaseController class, compile it and test that it works.
You should now have three URLs that respond, where <name> is any word that then gets printed on the page.


http://localhost:8080/assignment2_<userid>/hello/<name>
http://localhost:8080/assignment2_<userid>/welcome/<name>
http://localhost:8080/assignment2_<userid>/

UIO’s git repository

Now it’s time to check in your first version of the assignment into the GIT repository at UIO. The site we will be using for you to check in assignments and work together on projects is here:

http://git.uio.no/git/

The web user interface is not very fancy, and your projects will not be available on the web unless you explicitly allow it. This course is about using the command line git, so a fancy web page is not necessary.You can find more information on this page (in Norwegian) 

This is what you need to do:

First create a file in your project root (where your pom.xml file is) called .gitignore
This file prevents Git from checking in files we don’t want in the revision control system, such as build files, project settings etc. Such local files that are not relevant to share should not be checked in (people will give you a lot of hassle in your future jobs if you do this wrong.).
/.gitignore (same directory as your pom.xml file)

target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse

Create your own Git branch. First read some documentation to get an overview, but remember that you’ll be running towards a git repository on UIO, not github or Bitbucket, so the URLs will be different. Look through the lecture presentation from the first lecture (part III) to see how to set up GIT with your email and username.

The example assumes that the project directory containing your pom.xml file is called ‘assignment2’, and that you are in that directory. Since we’re adding already existing files, we can’t use git clone as in the lecture notes. We’ll set up a local repository by using git init, and then create the remote repository.

$ git init
$ git remote add origin gitolite@git.uio.no:inf5750/<your-uio-user-name>/assignment2_<your-uio-user-name>
$ git fetch origin
This creates an empty, remote repository and it needs to have same name as your project-directory, or it’ll put it into a different directory.
$ git status (just for fun)
$ git add .

This command adds all your files to the list of files handled by version management. The .gitignore file is important now, since it stops git from adding files you don’t want shared. Some developers would claim you should never just add all files, but just add explicit files.

$ git status (just for fun)
$ git commit -m “First commit of assignment2”

(puts your files into the local repository)


Edit the files you want to edit. If you add files, remember to run ‘git add’ to tell Git you want them under version control.
Now you want to push your local repository to the online repository:

$ git push origin master

Now for fun, you can change a file a bit. Maybe create a README-file? And add it, commit it and push to the central repository again.

$ git add .
$ git commit -m “I have changed these things … “ (this will upload your files)
$ git pull origin master
$ git push origin master

Download the git cheat sheet

The next part of the assignment will be adding database support to your simple web application, and you will update your remote repository with the new code after finishing that stage. You must submit files to the external repository so that the group teacher can see that you’ve done the first part of the assignment.

Hibernate

In this part of the assignment, you’ll be adding database access to your new web application. For this purpose, we will be using Hibernate, which is a framework that translates between a relational database and Java objects. The framework handles a lot of the details of doing database work, so that you can focus on making great web applications. In this assignment, we will be using only one table and one object mapping, but Hibernate can be used to represent quite advanced java object models into a relational database.

Hibernate is used a lot both in open source projects and in professional companies, so knowing how to use it will be useful for you later on. It is also used in DHIS2.

First let us update the pom.xml file, so that Maven knows which libraries to download and compile with.
/pom.xml (you may want to change to assignment2_<username> if you’ve used this above)

Remember: To run mvn install after updating pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>no.uio.inf5750</groupId>
        <artifactId>assignment2</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>assignment2 Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <properties>
                <spring.version>3.2.3.RELEASE</spring.version>
                <junit.version>4.11</junit.version>
                <jdk.version>1.6</jdk.version>
                <hibernate.version>3.5.1-Final</hibernate.version>
        </properties>
        <repositories>
                <repository>
                        <id>JBoss</id>
                        <url>https://repository.jboss.org/nexus/content/groups/public/</url>
                </repository>
        </repositories>
        <dependencies>
                <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <version>${junit.version}</version>
                        <scope>test</scope>
                </dependency>
                <!-- Spring -->
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-core</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-context</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-tx</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-orm</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-webmvc</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <!-- Hibernate -->
                <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-core</artifactId>
                        <version>${hibernate.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-entitymanager</artifactId>
                        <version>${hibernate.version}</version>
                </dependency>
                <dependency>
                        <groupId>geronimo-spec</groupId>
                        <artifactId>geronimo-spec-jta</artifactId>
                        <version>1.0-M1</version>
                </dependency>
                <dependency>
                        <groupId>c3p0</groupId>
                        <artifactId>c3p0</artifactId>
                        <version>0.9.1.2</version>
                </dependency>
                <dependency>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                        <version>1.5.8</version>
                </dependency>
                <dependency>
                        <groupId>com.h2database</groupId>
                        <artifactId>h2</artifactId>
                        <version>1.2.136</version>
                </dependency>
                <dependency>
                        <groupId>postgresql</groupId>
                        <artifactId>postgresql</artifactId>
                        <version>8.4-701.jdbc4</version>
                </dependency>

                <dependency>
                        <groupId>javax.servlet</groupId>
                        <artifactId>javax.servlet-api</artifactId>
                        <version>3.1.0</version>
                        <scope>provided</scope>
                </dependency>

        </dependencies>
          <build>
        <finalName>assignment2</finalName>
<!--
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
            </plugin>
        </plugins>
-->
    </build>
</project>

You need to implement the Java objects that represent the database content. In this assignment, this object will be called Message.java. Create the following file:

/src/main/java/no/inf5750/assignment2/model/Message.java

package no.uio.inf5750.assignment2.model;
public class Message
{
    private int id;
    public Message()
    {
    }
    public int getId() {
                return id;
        }
        public void setId(int id) {
                this.id = id;
        }
        public String getContent() {
                return content;
        }
        public void setContent(String content) {
                this.content = content;
        }
        
private String content;
   
}

You have to tell Hibernate how to map this Java object Message.java into the database. This can be done using an XML file or by using annotations inside the Java object. In this example we’ll be using an XML file. Hibernate has many functions to allow various mappings of Java objects into the relational tables, but we’ll be using a pretty simple one. Create the following XML file. It basically says that the no.uio.inf5750.assignment2.model.Message object maps to a table called message, and that this table has the values ‘id’ and ‘content’.

/src/main/resources/hibernate/Message.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="no.uio.inf5750.assignment2.model.Message" table="message">
    <id name="id" column="id">
      <generator class="native"/>
    </id>
    <property name="content" not-null="true"/>
  </class>
</hibernate-mapping>

You then have to create some classes that you use to access the database. These are Database Access Objects (DAO). Because you may want to replace Hibernate with other database layers, or even use files to store the data, you will first create an interface that represents the data storage. You can see that this interface has methods for saving a message, getting a message of a certain id and getting the last saved message.

/src/main/java/no/inf5750/assignment2/dao/MessageDao.java

package no.uio.inf5750.assignment2.dao;
import no.uio.inf5750.assignment2.model.Message;
public interface MessageDao
{
    int save( Message message );
    Message get( int id );
    Message getLast();    
}

Then you implement a java object that implements actual methods for accessing Hibernate to do these methods. You don’t have to understand all the details of this yet, as it hasn’t been covered in lectures, but look at the class and try to understand what’s happening.


/src/main/java/no/inf5750/assignment2/dao/HibernateMessageDao.java

package no.uio.inf5750.assignment2.dao;
import java.util.List;
import no.uio.inf5750.assignment2.model.Message;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.Session;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class HibernateMessageDao
   implements MessageDao
{
    static Logger logger = Logger.getLogger(HibernateMessageDao.class);
    private SessionFactory sessionFactory;
    public void setSessionFactory( SessionFactory sessionFactory )
    {
        this.sessionFactory = sessionFactory;
    }
    public int save( Message message )
    {
        return (Integer) sessionFactory.getCurrentSession().save( message );
    }

   public Message get( int id )
    {
        return (Message) sessionFactory.getCurrentSession().get( Message.class, id );
    }
    public Message getLast()
    {
        Session session = sessionFactory.openSession();
        Transaction tx = null;
        Message message = null;
        try{
           tx = session.beginTransaction();
           @SuppressWarnings("unchecked")
           // This is an HQL query, not an SQL query (HQL is based on SQL, but is not 100% the same)
           List<Message> messages = session.createQuery("FROM Message ORDER by id DESC").list();
           if (!messages.isEmpty()) {
                   message = messages.iterator().next();
           }
           tx.commit();
        }catch (HibernateException e) {
           if (tx!=null) tx.rollback();
           logger.error("DB query failed", e);
        }finally {
           session.close();
        }
        return message;
    }
}

You now have an updated pom.xml file, a model object, a Hibernate mapping file, an interface for accessing the database and an implementation that actually does the work of accessing the database.

You now have to tell Spring how to insert the Hibernate objects you just created into the application. In this assignment we will be using an in-memory database called H2. It is a good way to develop and test applications, but for real live webapps, you’d want to use something else like Postgres. H2 can also store data in files, if you want a lightweight database for development that is persistent across runs.
In the xml file below we are also configuring some HIbernate properties, by using Spring to inject these properties into LocalSessionFactoryBean.
Also note that we are using Spring to tell HibernateMessageDao where it can find the SessionFactory that it uses to access Hibernate. You can see in the Java code of HibernateMessageDao that it looks like HibernateMessageDao is not set. In fact, Spring sets this property when it creates the HibernateMessageDao object. This config is into bottom of the file below.

/src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        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-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
 
        <context:component-scan base-package="no.uio.inf5750.assignment2" />
 
        <bean
                class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix">
                        <value>/WEB-INF/pages/</value>
                </property>
                <property name="suffix">
                        <value>.jsp</value>
                </property>
        </bean>
 
  <!-- Hibernate-part of assignment 2 -->
 
  <tx:annotation-driven transaction-manager="transactionManager"/>
 
  <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
    <property name="dataSource" ref="dataSource"/>
  </bean>
 
  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
          <list>
                <value>hibernate/Message.hbm.xml</value>
          </list>
    </property>
    <property name="hibernateProperties">
          <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
                <!--
        <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>  
        -->    
                <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
          </props>
    </property>
  </bean>
   
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
                
    <property name="driverClass" value="org.h2.Driver"/>    
    <property name="jdbcUrl" value="jdbc:h2:mem:inf5750;DB_CLOSE_ON_EXIT=FALSE"/>
        <property name="user" value="sa"/>
        <property name="password" value=""/>
        
    <!-- The postgres configuration is commented out. Left here as a hint for future assignments -->
    <!--
    <property name="driverClass" value="org.postgresql.Driver"/>
    <property name="jdbcUrl" value="jdbc:postgresql:product"/>
        <property name="user" value="sa"/>
        <property name="password" value="sa"/>
        -->         
  </bean>
 
  <bean id="messageDao" class="no.uio.inf5750.assignment2.dao.HibernateMessageDao">
    <property name="sessionFactory" ref="sessionFactory"/>
  </bean>
 
</beans>

You should also create a log4j property file. You can use this one as a template:

/src/main/resources/log4j.properties

# Configuration file for log4j
# Log to file setup
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = nf.log
log4j.appender.file.MaxFileSize = 100KB
log4j.appender.file.MaxBackupIndex = 3
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = * %-5p %d{ABSOLUTE} %m (%F [%t])%n
# Log to console setup
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = * %-5p %d{ABSOLUTE} %m (%F [%t])%n
# Categories (order: DEBUG, INFO, WARN, ERROR, FATAL)
log4j.rootCategory = WARN, console
log4j.category.no.uio.inf5750 = INFO

Now you have set up everything you need to access the database, and the last thing you need to do is to create a Controller file and JSP file that actually uses the database and presents it well as a web page. It would be good if you can create your own personal touch to these two files, but you can use the below files as a starting point. Make sure your application can both send and receive messages. You can’t just copy straight from the below box, since you’ll lose some of the changes you did on your own earlier.

/src/main/webapp/WEB-INF/pages/index.jsp (you may need to edit the URL the message is submitted to)

<html>
<body>
<h2>Leave a message</h2>
 
<h1>${message}</h1>

<form name="input" action="/assignment2/send" method="get">
Message content: <input type="text" name="content">
<input type="submit" value="Submit">
</form>

<p><a href="/assignment2/read">Get last message</a></p>
</body>
</html>

You can see that the below file has a Spring annotations called @Autowired. This annotation takes the only implementation of the MessageDao interface and puts it into the messageDao variable. You can then use messageDao to send and receive messages (save and retrieve from the database).

Don’t get confused by the variable called ‘model’. This is a variable used by the Spring MVC to give data to the JSP page, not a variable that’s part of the database model.

/src/main/java/no/uio/inf5750/assignment2/controller/BaseController.java (don’t just copy this file, since you’ll lose your earlier helloWorld work. Merge it with the earlier work.)

package no.uio.inf5750.assignment2.controller;
 
import no.uio.inf5750.assignment2.dao.MessageDao;
import no.uio.inf5750.assignment2.model.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
 
@Controller
@RequestMapping("/")
public class BaseController {
 
        @Autowired
        private MessageDao messageDao;
        
        /*
         * Intro page. No database interaction.
         */
        @RequestMapping(value="/", method = RequestMethod.GET)
        public String welcome(ModelMap model) {
 
                model.addAttribute("message", "Leave a message using the form");
                
                //Spring uses InternalResourceViewResolver and return back index.jsp
                return "index";
        }
 
        /*
         * Saves a message in the database
         */
        @RequestMapping(value="/send", method = RequestMethod.GET)
        public String send(@RequestParam(value="content") String content, ModelMap model) {
 
                Message msg = new Message();
                msg.setContent(content);
                int id = messageDao.save(msg);
                model.addAttribute("message", "Message id of stored message=" + id);
                return "index";
 
        }
        
        /*
         * Prints the last message entered
         */
        @RequestMapping(value="/read", method = RequestMethod.GET)
        public String read(ModelMap model) {
 
                Message message = messageDao.getLast();
                if (message != null) {
                        model.addAttribute("message", "The last message was: "+message.getContent());
                }
                else {
                        model.addAttribute("message", "No message found");                        
                }
 
                //Spring uses InternalResourceViewResolver and return back index.jsp
                return "index";
        }
        
        /*
         * Prints the message with a given id
         */
        @RequestMapping(value="/read/{id}", method = RequestMethod.GET)
        public String readId(@PathVariable int id, ModelMap model) {
 
                Message message = messageDao.get(id);
                if (message != null) {
                        model.addAttribute("message", "Message number "+id+" was: "+message.getContent());
                }
                else {
                        model.addAttribute("message", "No message found");                        
                }
 
                //Spring uses InternalResourceViewResolver and return back index.jsp
                return "index";
        }
        
}

Test that your code compiles and runs ok.

You should be getting a web page in your browser that lets you send and receive messages.

If you are getting the following error: “java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener”, have a look at this solution. Look at the solution involving setting Deployment assembly to Maven dependencies.

Now check in your code in your assignment2-repository. Use git push origin master (but of course, first add and commit files. Old files that are changed also need to be added again.)

You also need to go to Devilry and upload a text-file with the repository-URL into assignment 2. 

You are now finished with this assignment, but it would be useful for you to look through the files and make sure you understand them. It would be very good learning for you to research on your own how to move this onto using Postgres instead of the H2 in-memory database.

Published Aug. 30, 2015 10:28 PM - Last modified Aug. 17, 2020 7:35 PM

Log in to comment