Skip to content
Snippets Groups Projects
Commit 9ec252d0 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

An alternative web server implementation using Jersey and JAX-RS

parent 03e26d9a
No related branches found
No related tags found
No related merge requests found
Showing
with 937 additions and 32 deletions
......@@ -15,6 +15,9 @@
<module>app.core</module>
<module>FxMapControl</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.gr1800.web.server.jaxrs.jaxrs.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-gr1800.web.server.jaxrs</artifactId>
<packaging>war</packaging>
<parent>
<groupId>tdt4140-gr1800</groupId>
<artifactId>tdt4140-gr1800</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-gr1800</groupId>
<artifactId>tdt4140-gr1800.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>
<systemProperties>
<systemProperty>
<name>data.locations</name>
<value>file:${project.basedir}/src/test/resources/tdt4140/gr1800/web/server/geoLocations.json</value>
</systemProperty>
</systemProperties>
</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.gr1800.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.gr1800.app.core.GeoLocation;
import tdt4140.gr1800.app.core.GeoLocations;
import tdt4140.gr1800.app.core.LatLong;
import tdt4140.gr1800.app.core.Person;
import tdt4140.gr1800.app.db.IdProvider;
import tdt4140.gr1800.app.json.GeoLocationDeserializer;
import tdt4140.gr1800.app.json.GeoLocationSerializer;
import tdt4140.gr1800.app.json.GeoLocationsDeserializer;
import tdt4140.gr1800.app.json.GeoLocationsSerializer;
import tdt4140.gr1800.app.json.LatLongDeserializer;
import tdt4140.gr1800.app.json.LatLongSerializer;
import tdt4140.gr1800.app.json.PersonDeserializer;
import tdt4140.gr1800.app.json.PersonSerializer;
@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GeoObjectMapperProvider implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
private final PersonSerializer personSerializer;
public GeoObjectMapperProvider() {
personSerializer = new PersonSerializer();
final SimpleModule module = new SimpleModule()
.addSerializer(new LatLongSerializer())
.addSerializer(new GeoLocationSerializer())
.addSerializer(new GeoLocationsSerializer())
.addSerializer(personSerializer)
.addDeserializer(LatLong.class, new LatLongDeserializer())
.addDeserializer(GeoLocation.class, new GeoLocationDeserializer())
.addDeserializer(GeoLocations.class, new GeoLocationsDeserializer())
.addDeserializer(Person.class, new PersonDeserializer());
objectMapper = new ObjectMapper()
.registerModule(module);
}
public void setPersonIdProvider(final IdProvider<Person> idProvider) {
personSerializer.setIdProvider(idProvider);
}
@Override
public ObjectMapper getContext(final Class<?> type) {
return objectMapper;
}
}
package tdt4140.gr1800.web.server.jaxrs;
import java.util.Collection;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Providers;
import com.fasterxml.jackson.databind.ObjectMapper;
import tdt4140.gr1800.app.core.GeoLocations;
import tdt4140.gr1800.app.core.Person;
import tdt4140.gr1800.app.db.IDbAccess;
@Path("geo")
public class GeoService {
@Inject
IDbAccess dbAccess;
protected IDbAccess getDbAccess() {
return dbAccess;
}
@Context
private Providers providers;
@PostConstruct
protected void ensureIdProvider() {
final ContextResolver<ObjectMapper> resolver = providers.getContextResolver(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
if (resolver instanceof GeoObjectMapperProvider) {
((GeoObjectMapperProvider) resolver).setPersonIdProvider(getDbAccess().getPersonIdProvider());
}
}
// REST URL structure, according to https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/
// persons/<id>/geoLocations/<num>/geoLocations/<num>
// GET variants
// persons: Get all Person objects. Do we allow that? Should we return a list of <id> values or all the person entities (with some subset of properties)
// persons/<id>: Get a specific Person object
// persons/name or email: Get a specific Person object, with the provided name or email (with a '@')
// persons/<id>/geoLocations: Get all the GeoLocations objects, with (some subset of) properties
// persons/<id>/geoLocations/<num>: Get a specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations: Get all GeoLocation objects, with (some subset of) properties
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Get a specific GeoLocation object
@GET
@Path("/persons")
@Produces(MediaType.APPLICATION_JSON)
public Collection<Person> getPersons() {
// System.out.println("getPersons");
return getDbAccess().getAllPersons(false);
}
@GET
@Path("/persons/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Person getPerson(@PathParam("id") final String idOrKey) {
// System.out.println("getPerson: " + idOrKey);
Person person = null;
try {
final Integer num = Integer.valueOf(idOrKey);
person = getDbAccess().getPerson(num, false);
} catch (final NumberFormatException e) {
person = (idOrKey.contains("@") ? getDbAccess().getPersonByEmail(idOrKey, false) : getDbAccess().getPersonByName(idOrKey, false));
}
return person;
}
@GET
@Path("/persons/{id}/geoLocations")
@Produces(MediaType.APPLICATION_JSON)
public Collection<GeoLocations> getGeoLocations(@PathParam("id") final String idOrKey) throws RuntimeException {
// System.out.println("getGeoLocations: " + idOrKey);
final Person person = getDbAccess().getPerson(Integer.valueOf(idOrKey), false);
return getDbAccess().getGeoLocations(person, false);
}
@GET
@Path("/persons/{id}/geoLocations/{num}")
@Produces(MediaType.APPLICATION_JSON)
public GeoLocations getGeoLocation(@PathParam("id") final int id, @PathParam("num") final int num) throws RuntimeException {
// System.out.println("getGeoLocation: " + id + "," + num);
final Person person = getDbAccess().getPerson(id, false);
final int geoNum = 0;
for (final GeoLocations geoLocations : getDbAccess().getGeoLocations(person, false)) {
if (geoNum == num) {
return geoLocations;
}
}
return null;
}
// POST variants
// persons: Create a new Person object, with properties in the payload
// persons/<id>: Not allowed
// persons/<id>/geoLocations: Create a new GeoLocations object, with properties in the payload
// persons/<id>/geoLocations/<num>: Not allowed
// persons/<id>/geoLocations/<num>/geoLocations: Create a new GeoLocation object, with properties in the payload
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Not allowed
@POST
@Path("/persons")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Person createPerson(final Person person, @Context final Providers providers) {
final Person dbPerson = getDbAccess().createPerson(person.getName(), person.getEmail());
return dbPerson;
}
// PUT variants
// persons: Not allowed
// persons/<id>: Update specific Person object
// persons/<id>/geoLocations: Not allowed
// persons/<id>/geoLocations/<num>: Update specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations: Not allowed
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Update specific GeoLocation object
// DELETE variants
// persons: Not allowed
// persons/<id>: Delete specific Person object
// persons/<id>/geoLocations: Delete all GeoLocations objects?
// persons/<id>/geoLocations/<num>: Delete specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations: Delete all GeoLocation objects?
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Delete specific GeoLocation object
}
package tdt4140.gr1800.web.server.jaxrs;
import java.sql.SQLException;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import tdt4140.gr1800.app.db.DbAccessImpl;
import tdt4140.gr1800.app.db.IDbAccess;
public class GeoServiceConfig extends ResourceConfig {
public GeoServiceConfig() {
packages("tdt4140.gr1800.web.server.jaxrs");
register(GeoService.class);
register(GeoObjectMapperProvider.class);
register(JacksonFeature.class);
// https://stackoverflow.com/questions/16216759/dependency-injection-with-jersey-2-0
register(new AbstractBinder() {
@Override
protected void configure() {
bind(getDbAccess()).to(IDbAccess.class);
}
});
}
private IDbAccess dbAccess;
public IDbAccess getDbAccess() {
if (dbAccess == null) {
String dbConnectionUrl = "jdbc:hsqldb:mem:" + getClass().getName();
final Object dbConnectionParam = getProperty("dbConnectionURL");
if (dbConnectionParam != null) {
dbConnectionUrl = String.valueOf(dbConnectionParam);
}
try {
final DbAccessImpl dbAccess = new DbAccessImpl(dbConnectionUrl);
dbAccess.executeStatements("schema.sql", false);
this.dbAccess = dbAccess;
} catch (final SQLException e) {
throw new RuntimeException("Error when initializing database connection (" + dbConnectionUrl + "): " + e, e);
}
}
return dbAccess;
}
// private ObjectMapper objectMapper;
//
// public ObjectMapper getObjectMapper() {
// if (objectMapper == null) {
// final PersonSerializer personSerializer = new PersonSerializer();
// personSerializer.setIdProvider(getDbAccess().getPersonIdProvider());
// final SimpleModule module = new SimpleModule()
// .addSerializer(new LatLongSerializer())
// .addSerializer(new GeoLocationSerializer())
// .addSerializer(new GeoLocationsSerializer())
// .addSerializer(personSerializer)
// .addDeserializer(LatLong.class, new LatLongDeserializer())
// .addDeserializer(GeoLocation.class, new GeoLocationDeserializer())
// .addDeserializer(GeoLocations.class, new GeoLocationsDeserializer())
// .addDeserializer(Person.class, new PersonDeserializer());
// objectMapper = new ObjectMapper()
// .registerModule(module);
// }
// return objectMapper;
// }
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
metadata-complete="false" version="3.1">
<!--
https://stackoverflow.com/questions/38639425/basic-jersey-webservice-with-maven-jetty-plugin
-->
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>tdt4140.gr1800.web.server.jaxrs.GeoServiceConfig</param-value>
</init-param>
<!--
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
-->
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
package tdt4140.gr1800.web.server.jaxrs;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import tdt4140.gr1800.app.core.Person;
public class GeoServiceIT {
private ObjectMapper objectMapper;
@Before
public void setUp() {
objectMapper = new GeoObjectMapperProvider().getContext(getClass());
}
private HttpURLConnection createUrlConnection(final String path) {
try {
return (HttpURLConnection) (new URL("http://localhost:8080/jax-rs/geo/" + path).openConnection());
} catch (final MalformedURLException e) {
throw new RuntimeException(e);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
protected Collection<Person> getPersons(final ArrayNode arrayNode) throws JsonProcessingException {
final Collection<Person> persons = new ArrayList<Person>();
for (final JsonNode childNode : arrayNode) {
persons.add(objectMapper.treeToValue(childNode, Person.class));
}
return persons;
}
protected int testPerson(final InputStream input, final Person person) throws Exception {
final JsonNode jsonTree = objectMapper.readTree(input);
Assert.assertTrue(jsonTree instanceof ObjectNode);
Assert.assertTrue(((ObjectNode) jsonTree).has("id"));
final JsonNode idNode = ((ObjectNode) jsonTree).get("id");
Assert.assertTrue(idNode instanceof ValueNode);
final int id = (idNode instanceof NumericNode ? ((NumericNode) idNode).asInt() : Integer.valueOf(idNode.asText()));
Assert.assertTrue(isPerson(person, objectMapper.treeToValue(jsonTree, Person.class)));
return id;
}
protected void testGetPerson(final int id, final Person person) throws Exception {
final HttpURLConnection con = createUrlConnection("persons/" + id);
con.setRequestMethod("GET");
con.setDoInput(true);
try (InputStream conIn = con.getInputStream()) {
testPerson(conIn, person);
}
}
protected boolean isPerson(final Person person, final Person conPerson) {
return person.getName().equals(conPerson.getName()) && person.getEmail().equals(conPerson.getEmail());
}
protected void testGetPersons(final Person... persons) throws Exception {
final HttpURLConnection con = createUrlConnection("persons");
con.setRequestMethod("GET");
con.setDoInput(true);
try (InputStream conIn = con.getInputStream()) {
final JsonNode jsonTree = objectMapper.readTree(conIn);
Assert.assertTrue(jsonTree instanceof ArrayNode);
final Collection<Person> conPersons = getPersons((ArrayNode) jsonTree);
outer: for (final Person person : persons) {
for (final Person conPerson : conPersons) {
if (isPerson(person, conPerson)) {
continue outer;
}
}
Assert.fail();
}
}
}
@Test
public void testCreatePersonGetPerson() throws Exception {
final Person person = new Person();
person.setName("Hallvard");
person.setEmail("hal@ntnu.no");
final HttpURLConnection con = createUrlConnection("persons");
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
objectMapper.writeValue(out, person);
out.close();
final byte[] bytes = out.toByteArray();
con.setFixedLengthStreamingMode(bytes.length);
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.connect();
try (OutputStream conOut = con.getOutputStream()) {
conOut.write(bytes);
}
try (InputStream conIn = con.getInputStream()) {
final int id = testPerson(conIn, person);
testGetPerson(id, person);
}
}
@Test
public void testCreatePersonGetPersons() throws Exception {
final Person person = new Person();
person.setName("Hallvard");
person.setEmail("hallvard.traetteberg@gmail.com");
final HttpURLConnection con = createUrlConnection("persons");
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
objectMapper.writeValue(out, person);
out.close();
final byte[] bytes = out.toByteArray();
con.setFixedLengthStreamingMode(bytes.length);
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.connect();
try (OutputStream conOut = con.getOutputStream()) {
conOut.write(bytes);
}
try (InputStream conIn = con.getInputStream()) {
testGetPersons(person);
}
}
}
<?xml version="1.0"?>
<gpx
version="1.0"
creator="VB Net GPS: vermeiren-willy@pandora.be"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/0"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<metadata>
<bounds minlat="51.396017" minlon="4.498043" maxlat="51.430402" maxlon="4.556108"/>
</metadata>
<wpt lat="51.39709" lon="4.501519">
<name>START</name>
</wpt>
<rte>
<name>Achterbroek naar De Maatjes 13 km RT</name>
<rtept lat="51.39709" lon="4.501519">
<name>1</name>
<cmt>1</cmt>
</rtept>
<rtept lat="51.398635" lon="4.502678">
<name>2</name>
<cmt>2</cmt>
</rtept>
<rtept lat="51.405072" lon="4.498043">
<name>3</name>
<cmt>3</cmt>
</rtept>
<rtept lat="51.417346" lon="4.515038">
<name>4</name>
<cmt>4</cmt>
</rtept>
<rtept lat="51.41932" lon="4.513879">
<name>5</name>
<cmt>5</cmt>
</rtept>
<rtept lat="51.421552" lon="4.523535">
<name>6</name>
<cmt>6</cmt>
</rtept>
<rtept lat="51.423011" lon="4.522848">
<name>7</name>
<cmt>7</cmt>
</rtept>
<rtept lat="51.423826" lon="4.5295">
<name>8</name>
<cmt>8</cmt>
</rtept>
<rtept lat="51.427002" lon="4.528513">
<name>9</name>
<cmt>9</cmt>
</rtept>
<rtept lat="51.430402" lon="4.552363">
<name>10</name>
<cmt>10</cmt>
</rtept>
<rtept lat="51.426229" lon="4.555399">
<name>11</name>
<cmt>11</cmt>
</rtept>
<rtept lat="51.426015" lon="4.554734">
<name>12</name>
<cmt>12</cmt>
</rtept>
<rtept lat="51.423569" lon="4.556108">
<name>13</name>
<cmt>13</cmt>
</rtept>
<rtept lat="51.41932" lon="4.546237">
<name>14</name>
<cmt>14</cmt>
</rtept>
<rtept lat="51.410952" lon="4.534092">
<name>15</name>
<cmt>15</cmt>
</rtept>
<rtept lat="51.406231" lon="4.543018">
<name>16</name>
<cmt>16</cmt>
</rtept>
<rtept lat="51.396695" lon="4.515966">
<name>17</name>
<cmt>17</cmt>
</rtept>
<rtept lat="51.396017" lon="4.515853">
<name>18</name>
<cmt>18</cmt>
</rtept>
<rtept lat="51.397133" lon="4.502635">
<name>19</name>
<cmt>19</cmt>
</rtept>
</rte>
</gpx>
<?xml version="1.0"?>
<gpx
version="1.0"
creator="VB Net GPS: vermeiren-willy@pandora.be"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/0"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<metadata>
<bounds minlat="51.396017" minlon="4.498043" maxlat="51.430402" maxlon="4.556108"/>
</metadata>
<wpt lat="51.39709" lon="4.501519">
<name>START</name>
</wpt>
<trk>
<name>Achterbroek naar De Maatjes 13 km TR</name>
<trkseg>
<trkpt lat="51.39709" lon="4.501519">
<name>1</name>
</trkpt>
<trkpt lat="51.397705" lon="4.501452">
<name>2</name>
</trkpt>
<trkpt lat="51.398635" lon="4.502678">
<name>3</name>
</trkpt>
<trkpt lat="51.404042" lon="4.498472">
<name>4</name>
</trkpt>
<trkpt lat="51.405072" lon="4.498043">
<name>5</name>
</trkpt>
<trkpt lat="51.405456" lon="4.499259">
<name>6</name>
</trkpt>
<trkpt lat="51.417346" lon="4.515038">
<name>7</name>
</trkpt>
<trkpt lat="51.41932" lon="4.513879">
<name>8</name>
</trkpt>
<trkpt lat="51.421552" lon="4.523535">
<name>9</name>
</trkpt>
<trkpt lat="51.423011" lon="4.522848">
<name>10</name>
</trkpt>
<trkpt lat="51.423826" lon="4.5295">
<name>11</name>
</trkpt>
<trkpt lat="51.427002" lon="4.528513">
<name>12</name>
</trkpt>
<trkpt lat="51.427131" lon="4.534478">
<name>13</name>
</trkpt>
<trkpt lat="51.426819" lon="4.53744">
<name>14</name>
</trkpt>
<trkpt lat="51.430402" lon="4.552363">
<name>15</name>
</trkpt>
<trkpt lat="51.426229" lon="4.555399">
<name>16</name>
</trkpt>
<trkpt lat="51.426015" lon="4.554734">
<name>17</name>
</trkpt>
<trkpt lat="51.423569" lon="4.556108">
<name>18</name>
</trkpt>
<trkpt lat="51.423097" lon="4.553981">
<name>19</name>
</trkpt>
<trkpt lat="51.41932" lon="4.546237">
<name>20</name>
</trkpt>
<trkpt lat="51.410952" lon="4.534092">
<name>21</name>
</trkpt>
<trkpt lat="51.406231" lon="4.543018">
<name>22</name>
</trkpt>
<trkpt lat="51.396695" lon="4.515966">
<name>23</name>
</trkpt>
<trkpt lat="51.396017" lon="4.515853">
<name>24</name>
</trkpt>
<trkpt lat="51.396858" lon="4.506495">
<name>25</name>
</trkpt>
<trkpt lat="51.397133" lon="4.502635">
<name>26</name>
</trkpt>
</trkseg>
</trk>
</gpx>
[
{
"name" : "1",
"locations" : [
{ "latitude" : "63", "longitude" : "10" },
[ "63.1", "10.1" ]
]
},
{
"name" : "2",
"path" : "true",
"locations" : [
{ "latitude" : "64", "longitude" : "11" },
[ "64.1", "11.1" ]
]
}
]
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" creator="Oregon 400t" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<metadata>
<link href="http://www.garmin.com">
<text>Garmin International</text>
</link>
<time>2009-10-17T22:58:43Z</time>
</metadata>
<trk>
<name>Example GPX Document</name>
<trkseg>
<trkpt lat="47.644548" lon="-122.326897">
<ele>4.46</ele>
<time>2009-10-17T18:37:26Z</time>
</trkpt>
<trkpt lat="47.644548" lon="-122.33">
<ele>4.94</ele>
<time>2009-10-17T18:37:31Z</time>
</trkpt>
<trkpt lat="47.65" lon="-122.33">
<ele>6.87</ele>
<time>2009-10-17T18:37:34Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
......@@ -3,7 +3,9 @@ package tdt4140.gr1800.web.server;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import javax.servlet.ServletException;
......@@ -91,23 +93,33 @@ public class GeoServlet extends HttpServlet {
// persons/<id>/geoLocations: Get all the GeoLocations objects, with (some subset of) properties
// persons/<id>/geoLocations/<num>: Get a specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations: Get all GeoLocation objects, with (some subset of) properties
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Get a specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Get a specific GeoLocation object
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
final HttpMethod method = new GetMethod(rootEntity);
doRequest(request, new GetMethod(rootEntity), false, true, response);
}
protected void doRequest(final HttpServletRequest request, final HttpMethod method, final boolean jsonInput, final boolean jsonOutput, final HttpServletResponse response) throws ServletException, IOException {
final JsonNode jsonNode = (jsonInput ? objectMapper.readTree(request.getInputStream()) : null);
method.setPayload(jsonNode);
final Object result = method.doMethod(getPathSegments(request));
if (result == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
} else {
respondWithJson(response, result);
response.setStatus(HttpServletResponse.SC_OK);
if (jsonOutput) {
respondWithJson(response, result);
} else {
response.setStatus(HttpServletResponse.SC_OK);
}
}
}
protected void respondWithJson(final HttpServletResponse response, final Object result) {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
try (OutputStream output = response.getOutputStream()) {
response.setStatus(HttpServletResponse.SC_OK);
objectMapper.writerWithDefaultPrettyPrinter().writeValue(output, result);
} catch (final Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
......@@ -119,8 +131,10 @@ public class GeoServlet extends HttpServlet {
if (path == null) {
throw new ServletException("Path cannot be empty");
}
final Iterator<String> segments = Arrays.asList(path.split("\\/")).iterator();
return segments;
final Collection<String> segments = new ArrayList<String>(Arrays.asList(path.split("\\/")));
// remove empty segments
while (segments.remove(""));
return segments.iterator();
}
// POST variants
......@@ -133,15 +147,7 @@ public class GeoServlet extends HttpServlet {
@Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
final HttpMethod method = new PostMethod(rootEntity);
final JsonNode jsonNode = objectMapper.readTree(request.getInputStream());
method.setPayload(jsonNode);
final Object result = method.doMethod(getPathSegments(request));
if (result == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
} else {
respondWithJson(response, result);
}
doRequest(request, new PostMethod(rootEntity), true, true, response);
}
// PUT variants
......@@ -150,19 +156,11 @@ public class GeoServlet extends HttpServlet {
// persons/<id>/geoLocations: Not allowed
// persons/<id>/geoLocations/<num>: Update specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations: Not allowed
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Update specific GeoLocations object
// persons/<id>/geoLocations/<num>/geoLocations/<num>: Update specific GeoLocation object
@Override
protected void doPut(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
final HttpMethod method = new PutMethod(rootEntity);
final JsonNode jsonNode = objectMapper.readTree(request.getInputStream());
method.setPayload(jsonNode);
final Object result = method.doMethod(getPathSegments(request));
if (result == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
} else {
respondWithJson(response, result);
}
doRequest(request, new PutMethod(rootEntity), true, true, response);
}
// DELETE variants
......@@ -175,12 +173,6 @@ public class GeoServlet extends HttpServlet {
@Override
protected void doDelete(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
final HttpMethod method = new DeleteMethod(rootEntity);
final Object result = method.doMethod(getPathSegments(request));
if (result == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
} else {
respondWithJson(response, result);
}
doRequest(request, new DeleteMethod(rootEntity), false, true, response);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment