INF5750 - Assignment 2

Deadline: September 23th, 23:59

You must pass this assignment to pass the course. Meet up to your lab sessions to ask your group teacher if you have any questions.

Technologies involved

Spring, Hibernate, JUnit, JavaScript and Maven.

Please read through before starting

Note: you will not be able to run this application before you have made the hibernate configurations and created/implemented the dao and service objects.

Overview

In this assignment you will be implementing functionality for a simple web-based student system. The system consists of three layers: persistence, service, and presentation layers. Your task is to implement the functionality of the first two layers. Expected functionalities of the two layers are defined in interfaces which are provided for you. You need to implement these interfaces and create unit tests which prove that your implementations are correct according to the interfaces. The graphical user interface (presentation layer) is provided, and can be configured to use your implementations to get a fully working system.

Case description

The case is a simple student system for keeping track of students, their courses and location (e.g. where they live). Students can attend courses and courses have attendants. To keep the model simple there is no time aspect in the system. The system does not claim to be a realistic student system.

Provided source code

Note: You’re not allowed to change any of the provided code except the root pom.xml and the pom.xml of the GUI project. Also, if you want to use Hibernate annotations, you can annotate the classes in the api project. See the detailed description below for information about where to find the initial project code.

Run mvn install in project root BEFORE importing to eclipse.

assignment2-api

The API project contains the model and the interfaces you will be implementing. The model consists of two classes: Student and Course. The properties of these classes are kept to a minimum to make life simpler. The Student has a Set of Courses. The Course has a Set of Students (attendants), so the Student-Course relation is bidirectional. For each of these classes you will find a corresponding DAO interface (Data Access Object) with simple methods to persist (“store”) and to retrieve persisted objects. The main functionality of the system is defined by the StudentSystem service interface. Your implementation of this interface will use the DAOs to persist objects.

assignment2-gui

The GUI project contains a working GUI based on Spring MVC, though with no actual functionality. The GUI will use your implementation of the API when you run it.

Requirements

All your code must be in a separate Maven project (assignment2-deliverable) alongside the provided modules. You must upload your project to Devilry. To make it possible for your group teachers to differentiate, please call your project folder assignment2_<youruserid>

You must create hibernate mapping files that enable Hibernate to map the assignment2-api model (java interfaces) to the relational database tables and columns. There will be mapping files for the model files Course and Student. It is useful to draw up a diagram of how these relate to help you create the mapping files.

The Data Access Object (DAO) interfaces must be implemented according to the description in the interfaces and in the assignment, using Hibernate for persistence. Usage of Spring ORM/Hibernate support is mandatory. The DAO implementation provides methods to create, save and do other operations on the database, using Hibernate’s “sessionFactory.getCurrentSession().” as the interface to the database. It’s probably simplest to autowire the sessionFactory into your DAO implementations.

The service interface (StudentSystem) must be implemented, and must use the DAO interfaces for storing and retrieving the model objects. This is a higher level interface that provides operations that involve Courses and Students. The interface is already defined in the api-package, but you have to create an implementation of it.

You must write unit tests for the service layer (StudentSystem) according to the defined behaviour of the implementations. The tests must run successfully with Maven and use Spring to instantiate the components which are going to be tested. Usage of Spring test support is mandatory.

The components of the system must be wired together using the Spring container and the dependency injection principle. You can choose whether to use the XML or annotation based configuration.

The code must have a consistent and readable code style. (Use Eclipse CTRL-SHIFT-F to help format your code). Using the formatting tool of your IDE is a very good practice to make good-looking code fast.

The provided GUI must be made fully functional.

The directory structure of the reference implementation is shown in the figure below:

Skjermbilde 2016-09-07 kl. 19.03.14.png

What should the user interface look like?

You do not have to implement a user interface, since the project already comes with one. Hint: Click ‘Init database’ to populate your db with some data.

You only need to implement the storage layer and the test classes. Here are some screenshots of the user interface:

Skjermbilde 2016-09-07 kl. 19.04.22.png

Skjermbilde 2016-09-07 kl. 20.07.58.png

Skjermbilde 2016-09-07 kl. 20.14.02.png

Which database to use

In Assignment 1, you used the in-memory database H2. You can also use H2 in this assignment, but many people will find it simpler to do the job of using Postgres instead. To use postgres, you need to install postgres on your computer (or get a UIO postgres account), create a database called for example ‘inf5750’ with a user ‘dhis’ and password ‘dhis’, and then reconfigure the beans.xml file in your deliverable to use Postgres instead of H2. If you do chose Postgres, please include a README file to inform us of your choice.

If you want to configure Postgres as your Hibernate-database, your beans.xml would contain this configuration (this is not the complete beans.xml). In this case, the database is called inf5750, the user=dhis and the password=dhis.

<property name="hibernateProperties">

        <props>

                <prop key="hibernate.show_sql">true</prop>

                <!-- <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>

<!--<property name="driverClass" value="org.h2.Driver" />

<property name="jdbcUrl" value="jdbc:h2:file:inf5750;DB_CLOSE_ON_EXIT=FALSE" />-->

<property name="jdbcUrl" value="jdbc:postgresql:inf5750" />

<property name="driverClass" value="org.postgresql.Driver" />

<property name="user" value="dhis" />

<property name="password" value="dhis" />

...

 

Hints and detailed description

The initial source code is available here

You now have a maven project consisting of three sub-projects. Two of them should remain unchanged (the assignment2-gui and assignment2-api). You should do all your work in the assignment2-deliverable, which you can see is almost empty now.

assignment2_<uio-user-id>/assignment2-api/

assignment2_<uio-user-id>/assignment2-gui/

assignment2_<uio-user-id>/assignment2-deliverable/

In order to implement and run unit tests you need a dependency to JUnit (junit) and a dependency to Spring (spring-test). Dependencies are added in your pom.xml files. Since you have sub-projects, you have a master pom in the root directory and sub-poms in the sub-directories. Check if you have dependencies for JUnit and spring-test in your deliverable pom.xml file. We have already given you a pom.xml file in the deliverable directory. Normally you have to write this yourself.

Opening up the project in Eclipse:

o Run mvn install from the root of the project (where pom.xml, assignment2-api, assignment2-gui, etc. is located).

o Import existing Maven project from the Eclipse GUI. File -> Import -> Existing Maven project.

In order to get the GUI working later on, check that your project is added as a dependency to the pom.xml in the assignment2-gui project.

It is a good habit to use Git while you are working with the code and to check in code locally often.

A screenshot of the reference is provided earlier in this assignment.

Your Hibernate implementations of the DAO interfaces should be named HibernateCourseDAO (and so on) and be placed in a package called no.uio.inf5750.assignment2.dao.hibernate.

Your implementation of the StudentSystem interface should be named DefaultStudentSystem and be placed in package called no.uio.inf5750.assignment2.service.impl.

Your StudentSystem test class (StudentSystemTest.java) should be placed in a package called no.uio.inf5750.assignment2.service in the “src/test/java” directory.

Look in the Maven lecture notes and/or assignment 1 to understand which directory structure you should follow when you build up your deliverable project. Note that the test classes do not reside together with the other src files, but in a separate directory called /src/test/java.  

The beans.xml file must go into a directory called src/main/resources/META-INF/assignment2/ for the main class in the GUI to find it. Note that this xml file could be called different names in different projects, but that many developers often use the name beans.xml since this is the main definition file for Spring-beans. This is where you configure sessionfactory, datasource, transaction manager and other beans like studentsystem, and the dao objects.

Your hibernate mapping files should have the format <interface-name>.hbm.xml, for example Course.hbm.xml and be placed in the src/main/resources/hibernate directory.

To get detailed instructions on how to set up the Spring (spring-orm) and Hibernate POM dependencies and how to use the Spring support for ORM/Hibernate and testing, please consult the Hibernate lecture slides.

To run the GUI, right-click the assignment2-gui project within Eclipse and choose ‘Run on server’. Look at assignment1 for more information. You can also run it within jetty, from command line by running ‘mvn jetty:run’ while in the assignment2-gui folder.(remember to run mvn clean install on in the root directory first) For this to work, there needs to be a jetty-plugin defined in the pom.

By default, Eclipse uses the dependencies from the local Maven repository. You may have to choose ‘Maven → update project’ within Eclipse when you’ve updated your pom files. You may also need to add Tomcat dependencies in the build path of your project.

If you are using Spring annotations you must provide a value to the DefaultStudentSystem class annotation like this for the GUI to find it: @Component(“defaultStudentSystem”)

Location page

To support a single web page which uses Javascript and REST to populate a table, we have a page called ‘Location’. This page should list all students, their courses and which location the system has them logged in as. The same page should be able to set the location of a selected student, using the geolocation functionality in your browser. To get this working, you have to go through a series of steps and fill in some missing gaps that we’ve left out.

In this part of the assignment you will be allowed to change both the API classes and the GUI classes, which is necessary to finish the assignment.

Adding location fields

Add the following private variables in the Student model object (in the API project), with appropriate getters and setters:

private String longitude;
private String latitude;

Add the following functions to the StudentSystem interface class:

void setStudentLocation(int studentId, String latitude, String longitude);

Do the necessary changes in the student.hbm.xml file to save longitude and latitude.

Implement the necessary method for the above interfaces in the DefaultStudentSystem class and it’s interface StudentSystem.

Write test classes to check that longitude and latitude is stored and can be retrieved correctly.

API Controller

In the no.uio.inf5750.assignment2.gui.controller package, create a class ApiController which implements web api interfaces at the following locations.

Resource URIs

These are the resources and methods that you should support in your API.

/api/student

Return a collection of all students, supporting at least the JSON format.(see below)

A challenge here is that the student refers to courses, which again refers to students. If you do nothing, your JSON will be endlessly large. So you have to stop the recursion by entering some annotations into the model objects.

There are two ways to prevent endless recursion.

Either using:

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")

This is the new way of doing it, but it produces JSON which is a bit strange. You could also use @JsonIgnore, which is the old way. Put @JsonIgnore on the variables you don’t want to be included in the JSON. For example, put these by the collections inside the Course model. That way, the student JSON will include courses, but the courses JSON will not include student.

The following is what your JSON should end up looking like (as an example - the elements may be ordered differently). Access your web server at http://localhost:8080/api/student.json, and you should get a JSON object returned. It might be empty “[]” if you have nothing in your database. If you like, you can use a browser extension to help format your JSON nicely.

[ { "courses" : [ { "courseCode" : "INF5750",
         "id" : 1,
         "name" : "Open Source Development"
       },
       { "courseCode" : "INF5761",
         "id" : 2,
         "name" : "Health management information systems"
       }
     ],
   "id" : 1,
   "latitude" : null,
   "longitude" : null,
   "name" : "John McClane"
 },
 { "courses" : [ { "courseCode" : "INF5750",
         "id" : 1,
         "name" : "Open Source Development"
       },
       { "courseCode" : "INF5761",
         "id" : 2,
         "name" : "Health management information systems"
       }
     ],
   "id" : 2,
   "latitude" : null,
   "longitude" : null,
   "name" : "Jane Fonda"
 }
]

/api/student/{student}/location

Set the location for a certain student. Use GET as a method and request-parameters longitude and latitude. For this method, also return a collection of all students. (If we were to stick strictly to REST, we’d post a JSON with the lat and long to update the location, instead of using a GET and request-parameters. Exactly how you implement it is not important, as long as you make it work. If you want to post a JSON, you can use @RequestBody <object> name as a function parameter in your MVC Java call, and Spring-MVC will parse the incoming JSON and populate that variable. You may also have to set headers = {"Content-type=application/json;charset=UTF-8"} in @RequestMapping annotation in the Java function call)

/api/course

Should return a collection of all courses, supporting at least the JSON format. It does not have to show the attendants, just a list of courses.

Example code

Method with @ReponseBody

In the previous assignment, the Controllers return a String for view name. In the api controller we will instead use @ResponseBody, to respond with data in the format the client requested.

@RequestMapping(value="/student/{user}", method = RequestMethod.GET)
@ResponseBody
public Student getStudentByUsername(@PathVariable String user,
       HttpServletRequest request,
       HttpServletResponse response) {
     
    Student student = studentService.getStudent(user);
    return student;
}

 

ContentNegotiatingViewResolver

ContentNegotiatingViewResolver does not resolve views itself, rather delegates to others. This way we can delegate the task of creating the JSON to jackson.

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">

         

            <property name="mediaTypes">

                <map>

                    <entry key="json" value="application/json" />

                    <entry key="xml" value="application/xml" />

               </map>

            </property>

        </bean>

        <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">

                <property name="contentNegotiationManager" ref="contentNegotiationManager"/>

 


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

Note: this is already added to the skeleton - take a look in mvc-dispatcher-servlet.xml in the assignment-gui module.

Doing necessary modifications to the HTML/Javascript files

When accessing the web pages, use Firefox/Chrome instead of the internal Eclipse browser.

The index.jsp now produces a page which doesn’t fill in student data on the server, but which calls a Javascript call that should fill in this data. The skeleton project contains the functions signatures, but lacks the body. You must implement these functions, and also the necessary AJAX call to actually call the web api on the server to get data.

The geolocation Javascript call and the AJAX call to save the student’s location onto the server. For help on check out this resource on geolocation.

You’ll find these empty functions in the assignment.js file in the assignment-gui module under src/main/webapp/js/, together with some other functions you don’t have to change.

Testing the Web API-enabled web page

Use Firefox/Chrome to test the web page. Don’t rely on the browser internal to Eclipse.

If you now see a web page with a list of students as the main page, and you’re able to set the location of individual students, with that location showing up in the table, you’ve finished the first part of the assignment.

Skjermbilde 2016-09-07 kl. 21.08.58.png

Showing a map

To include a map on the page, add the following script to the end of index.jsp

<script src="https://maps.googleapis.com/maps/api/js"></script>

Inside assignment.jsp, you’ll need to add the Javascript to draw the map.

var map;
function initialize_map() {
       var mapOptions = {
               zoom : 10,
               mapTypeId : google.maps.MapTypeId.ROADMAP
       };
       map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
       // Try HTML5 geolocation
       if (navigator.geolocation) {
               navigator.geolocation.getCurrentPosition(function(position) {
                       var pos = new google.maps.LatLng(position.coords.latitude,
                                       position.coords.longitude);
                       map.setCenter(pos);
               }, function() {
                       handleNoGeolocation(true);
               });
       } else {
               // Browser doesn't support Geolocation
               // Should really tell the user…
       }
}

You have to make sure the initialize_map() gets called when the page is loaded. See inside the index.jsp where the getStudentData() is loaded. Add initialize_map() there, so it is run when the page is finished loading.

It would be cool to implement a marker on the map where the students are. You do this by using the following code inside the loop which prints out the location values, inside the populateStudentTable function.

var myLatlng = new google.maps.LatLng(student.latitude, student.longitude);                        
var marker = new google.maps.Marker({
   position: myLatlng,
   map: map,
   title: student.name
});

Now you should get a map showing the location of the different students.

Skjermbilde 2016-09-07 kl. 21.11.30.png

Finished

Zip the whole project and upload it to Devilry before 23. September.