Assignment 3

Deadline Date October 25th, 23:59. Don't push to git after the deadline and remember to hand in the text file in devilry.

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.

Starting point

Start with the project you made in assignment 2b. There are some changes to the UI layer that you must merge into your code to support Javascript/REST/AJAX based UI. Whereas the assignment 2b had web pages generated on the server side using JSP, for assignment 3 we have added a single web page which uses Javascript and REST to populate a table. This is a page that is called ‘Location’ and it 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.

You will be downloading a new skeleton project, which is similar to assignment 2b, and you should copy your working assignment 2b deliverable into that as a sub-project. In this assignment you will be allowed to change both the API classes and the GUI classes. You will have to do this to finish the assignment.

Downloading the skeleton

Download the skeleton code from "gitolite@git.uio.no:inf5750/roland/assignment3-skeleton" by running the clone command (see assignment 2b how you then push this into your own personal repository under inf5750/<username> by deleting and adding new remotes). This skeleton code is a bit different from assignment 2b, but you should be able to copy your assignment 2 deliverable straight into the deliverable directory and run the project.

Postgres

Again, in this assignment you may use postgres (like assignment 2b), but you will pass also by using the in-memory database.

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. It should have the following format.

The problem 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 recursion.

Either using:

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

This is the new way of doing it, but it does produce a bit strange JSON. 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 and Degree models. 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 returned. It might be empty “[]” if you have nothing in your database. You can use this page or a Chrome extension to help format your JSON.

[ { "courses" : [ { "courseCode" : "INF5750",
          "id" : 1,
          "name" : "Open Source Development"
        },
        { "courseCode" : "INF5761",
          "id" : 2,
          "name" : "Health management information systems"
        }
      ],
    "degrees" : [  ],
    "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"
        }
      ],
    "degrees" : [  ],
    "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 attendents, just a list of courses.

/api/degree 

Should return a collection of all degrees, supporting at least the JSON format. You do not have to show the required courses or students as part of this list.

 

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

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

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
   <property name="mediaTypes">
       <map>
           <entry key="html" value="text/html"/>
           <entry key="json" value="application/json"/>
       </map>
   </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>

Jackson pom dependency

Jackson is a suite of data-processing tools for Java (and JVM platform), including the flagship streaming JSON parser / generator library, matching data-binding library (POJOs to and from JSON). You will use jackson to generate JSON from your POJOs. 

Add this to your main pom.xml

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.0.4</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.0.4</version>
</dependency>

Doing necessary modifications to the HTML/Javascript files

When accessing the web pages, use 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 Javascript to fill in the data, but lacks:

The AJAX call to actually call the web api on the server to get data. You must implement this.

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, together with some other functions you don’t have to change.

Testing the Web API-enabled web page 

Use 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.

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?v=3.exp&sensor=false"></script>

Add the following style inside the <head> … </head> tags, or make a separate css file to include the style.


<style>
html,body {
        height: 100%;
}
#map-canvas {
        height: 50%;
        padding-right: 15px;
        padding-left: 15px;
        margin-right: auto;
        margin-left: auto;
        width: 80%;
}
</style>

Now place a div-tag inside your page, where you want the map to appear.

<div id="map-canvas" class="container map"></div>

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…
        }
}

And 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.

Finished - upload your code

Upload both your server code to a new repository on gitolite@git.uio.no:inf5750/<username>/assignment3_<username>, and submit the URL within Devilry. Make sure you check Devilry for feedback from your group teacher, in case there is an error in your delivery.

 

Published Oct. 8, 2015 7:46 AM - Last modified Aug. 17, 2020 7:35 PM