Commit e1a40b28 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Extended template project with minimal domain and web-server.

parent 9ec252d0
Pipeline #77242 passed with stage
in 1 minute and 52 seconds
# Template project for the TDT4140 course, Spring 2018
This is a template for a JavaFX project with two sub-modules, one for the model and one for the UI. To use the template, copy the whole structure and systematically rename files and edit file contents to match your group number.
This is a template for a JavaFX and web-server(s) project with four sub-modules, one for the model, one for the UI and two variants of the web-server (plain HttpServlet and using JAX-RS. To use the template, copy the whole structure and systematically rename files and edit file contents to match your group number.
package tdt4140.gr18nn.app.core;
public class LatLong {
public final double latitude, longitude;
public LatLong(final double latitude, final double longitude) {
super();
this.latitude = latitude;
this.longitude = longitude;
}
public final static String SEPARATOR = ",";
@Override
public String toString() {
return latitude + SEPARATOR + longitude;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(latitude);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(longitude);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final LatLong other = (LatLong) obj;
return (Double.doubleToLongBits(latitude) == Double.doubleToLongBits(other.latitude) &&
Double.doubleToLongBits(longitude) == Double.doubleToLongBits(other.longitude));
}
public static LatLong valueOf(final String s) {
return valueOf(s, SEPARATOR);
}
public static LatLong valueOf(final String s, final String sep) {
final int pos = s.indexOf(sep);
if (pos < 0) {
throw new IllegalArgumentException("No '" + sep + "' in " + s);
}
final double lat = Double.valueOf(s.substring(0, pos).trim());
final double lon = Double.valueOf(s.substring(pos + sep.length()).trim());
return new LatLong(lat, lon);
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: :*/
/*:: This routine calculates the distance between two points (given the :*/
/*:: latitude/longitude of those points). It is being used to calculate :*/
/*:: the distance between two locations using GeoDataSource (TM) products :*/
/*:: :*/
/*:: Definitions: :*/
/*:: South latitudes are negative, east longitudes are positive :*/
/*:: :*/
/*:: Passed to function: :*/
/*:: lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees) :*/
/*:: lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees) :*/
/*:: Worldwide cities and other features databases with latitude longitude :*/
/*:: are available at http://www.geodatasource.com :*/
/*:: :*/
/*:: For enquiries, please contact sales@geodatasource.com :*/
/*:: :*/
/*:: Official Web site: http://www.geodatasource.com :*/
/*:: :*/
/*:: GeoDataSource.com (C) All Rights Reserved 2015 :*/
/*:: :*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
public static double distance(final double lat1, final double lon1, final double lat2, final double lon2) {
if (lon1 == lon2 && lat1 == lat2) {
return 0.0;
}
final double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
dist = Math.acos(dist);
// convert to degrees
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
// convert to meters
dist = dist * 1609.344;
return dist;
}
public static double distance(final LatLong latLong1, final LatLong latLong2) {
return distance(latLong1.latitude, latLong1.longitude, latLong2.latitude, latLong2.longitude);
}
public double distance(final LatLong latLong2) {
return distance(latitude, longitude, latLong2.latitude, latLong2.longitude);
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: This function converts decimal degrees to radians :*/
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
private static double deg2rad(final double deg) {
return (deg * Math.PI / 180.0);
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: This function converts radians to decimal degrees :*/
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
private static double rad2deg(final double rad) {
return (rad * 180 / Math.PI);
}
}
package tdt4140.gr18nn.app.json;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import tdt4140.gr18nn.app.core.LatLong;
public class LatLongDeserializer extends JsonDeserializer<LatLong> {
@Override
public LatLong deserialize(final JsonParser jsonParser, final DeserializationContext deserContext) throws IOException, JsonProcessingException {
final JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser);
return deserialize(jsonNode);
}
public LatLong deserialize(final JsonNode jsonNode) throws JsonProcessingException {
if (jsonNode instanceof ObjectNode) {
final ObjectNode objectNode = (ObjectNode) jsonNode;
final double latitude = objectNode.get(LatLongSerializer.LATITUDE_FIELD_NAME).asDouble();
final double longitude = objectNode.get(LatLongSerializer.LONGITUDE_FIELD_NAME).asDouble();
return new LatLong(latitude, longitude);
} else if (jsonNode instanceof ArrayNode) {
final ArrayNode locationArray = (ArrayNode) jsonNode;
if (locationArray.size() == 2) {
final double latitude = locationArray.get(0).asDouble();
final double longitude = locationArray.get(1).asDouble();
return new LatLong(latitude, longitude);
}
}
return null;
}
}
package tdt4140.gr18nn.app.json;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import tdt4140.gr18nn.app.core.LatLong;
public class LatLongSerializer extends JsonSerializer<LatLong> {
public static final String LONGITUDE_FIELD_NAME = "longitude";
public static final String LATITUDE_FIELD_NAME = "latitude";
@Override
public void serialize(final LatLong latLon, final JsonGenerator jsonGen, final SerializerProvider provider) throws IOException {
jsonGen.writeStartObject();
jsonGen.writeFieldName(LATITUDE_FIELD_NAME);
jsonGen.writeNumber(latLon.latitude);
jsonGen.writeFieldName(LONGITUDE_FIELD_NAME);
jsonGen.writeNumber(latLon.longitude);
jsonGen.writeEndObject();
}
}
# Resources used by the web server code
\ No newline at end of file
package tdt4140.gr18nn.app.core;
import org.junit.Assert;
import org.junit.Test;
public class LatLongTest {
@Test
public void testToString() {
LatLong latLong = new LatLong(63.0, 10.0);
Assert.assertEquals(Double.toString(63) + "," + Double.toString(10), latLong.toString());
}
@Test
public void testValueOf() {
testLatLong(LatLong.valueOf("63.0, 10.0"), 63.0, 10.0);
testLatLong(LatLong.valueOf("63.0, 10.0", ","), 63.0, 10.0);
testLatLong(LatLong.valueOf("63.0; 10.0", ";"), 63.0, 10.0);
}
private void testLatLong(LatLong latLong, double lat, double lon) {
Assert.assertEquals(lat, latLong.latitude, 0.0);
Assert.assertEquals(lon, latLong.longitude, 0.0);
}
@Test
public void testEquals() {
Assert.assertTrue(new LatLong(63.0, 10.0).equals(new LatLong(63.0, 10.0)));
Assert.assertFalse(new LatLong(10.0, 63.0).equals(new LatLong(63.0, 10.0)));
Assert.assertFalse(new LatLong(10.0, 63.0).equals(null));
Assert.assertFalse(new LatLong(10.0, 63.0).equals("10.0, 63.0"));
}
}
......@@ -14,5 +14,9 @@
<modules>
<module>app.core</module>
<module>app.ui</module>
<!--
<module>web.server</module>
-->
<module>web.server.jaxrs</module>
</modules>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>tdt4140.gr18nn.web.server.jaxrs</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
# web.server.jaxrs module - Web server providing a REST API to domain data, using JAX-RS implemented by Jersey
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>tdt4140-gr18nn.web.server.jaxrs</artifactId>
<packaging>war</packaging>
<parent>
<groupId>tdt4140-gr18nn</groupId>
<artifactId>tdt4140-gr18nn</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<jetty.version>9.4.8.v20171121</jetty.version>
<jersey.version>2.26</jersey.version>
</properties>
<dependencies>
<dependency>
<groupId>tdt4140-gr18nn</groupId>
<artifactId>tdt4140-gr18nn.app.core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<!--
Needed as of v. 2.26
See https://stackoverflow.com/questions/44088493/jersey-stopped-working-with-injectionmanagerfactory-not-found
-->
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- to use Jackson as provider for JSON media type -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-maven-plugin -->
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.8.v20171121</version>
<configuration>
<webApp>
<contextPath>/jax-rs</contextPath>
</webApp>
<scanIntervalSeconds>0</scanIntervalSeconds>
<stopKey>stopMe</stopKey>
<stopPort>9966</stopPort>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId> <!-- for starting jetty for integration tests -->
<version>2.16</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package tdt4140.gr18nn.web.server.jaxrs;
import java.util.ArrayList;
import java.util.List;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import tdt4140.gr18nn.app.core.LatLong;
public class LatLongApp extends ResourceConfig {
public LatLongApp() {
packages("tdt4140.gr18nn.web.server.jaxrs");
register(LatLongService.class);
register(LatLongObjectMapperProvider.class);
register(JacksonFeature.class);
register(new AbstractBinder() {
@Override
protected void configure() {
bind(LatLongApp.this);
}
});
}
final List<LatLong> geoLocations = new ArrayList<>();
}
package tdt4140.gr18nn.web.server.jaxrs;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import tdt4140.gr18nn.app.core.LatLong;
import tdt4140.gr18nn.app.json.LatLongDeserializer;
import tdt4140.gr18nn.app.json.LatLongSerializer;
@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class LatLongObjectMapperProvider implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
public LatLongObjectMapperProvider() {
final SimpleModule module = new SimpleModule()
.addSerializer(LatLong.class, new LatLongSerializer())
.addDeserializer(LatLong.class, new LatLongDeserializer());
objectMapper = new ObjectMapper()
.registerModule(module);
}
@Override
public ObjectMapper getContext(final Class<?> type) {
return objectMapper;
}
}
package tdt4140.gr18nn.web.server.jaxrs;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import tdt4140.gr18nn.app.core.LatLong;
@Path("latLong")
public class LatLongService {
@Inject
LatLongApp latLongApp;
protected List<LatLong> getLatLongs() {
return latLongApp.geoLocations;
}
@GET
@Path("/{num}")
@Produces(MediaType.APPLICATION_JSON)
public LatLong getLatLong(@PathParam("num") int geoLocNum) {
if (geoLocNum < 0) {
geoLocNum = getLatLongs().size() + geoLocNum;
}
return getLatLongs().get(geoLocNum);
}
@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public int addLatLongs(final List<LatLong> latLongs) {