Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • issue-10-fxmapcontrol
  • issue-13-gpx
  • issue-9-file-menu
  • master
4 results

Target

Select target project
  • bragearn/examples
  • johngu/examples
  • krisschn/examples
  • erikbd/examples
  • helenesm/examples
  • balazor/examples
  • htechter/examples
  • aslakho/examples
  • jonri/examples
  • andreski/examples
  • sigriksc/examples
  • norasbr/examples
  • jannash/examples
  • smledsaa/examples
  • mtorre/examples
  • tdt4140-staff/examples
16 results
Select Git revision
  • issue-10-fxmapcontrol
  • issue-13-gpx
  • issue-9-file-menu
  • master
  • patch-1
  • test
6 results
Show changes
Showing
with 1106 additions and 5 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"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the sun coding conventions from:
- the Java Language Specification at
http://java.sun.com/docs/books/jls/second_edition/html/index.html
- the Sun Code Conventions at http://java.sun.com/docs/codeconv/
- the Javadoc guidelines at
http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
- the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
- some best practices
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
Finally, it is worth reading the documentation.
-->
<module name="Checker">
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See
http://checkstyle.sourceforge.net/5.x/config.html#Checker
<property name="basedir" value="${basedir}"/>
-->
<property name="fileExtensions" value="java, properties, xml"/>
<!-- Checks that a package-info.java file exists for each package. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->
<module name="JavadocPackage"/>
<!-- Checks whether files end with a new line. -->
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile"/>
<!-- Checks that property files contain the same keys. -->
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
<module name="Translation"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="FileLength"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="FileTabCharacter"/>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="minimum" value="0"/>
<property name="maximum" value="0"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<!-- Checks for Headers -->
<!-- See http://checkstyle.sf.net/config_header.html -->
<!-- <module name="Header"> -->
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
<!-- <property name="fileExtensions" value="java"/> -->
<!-- </module> -->
<module name="TreeWalker">
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod"/>
<module name="JavadocType"/>
<module name="JavadocVariable"/>
<module name="JavadocStyle"/>
<!-- Checks for Naming Conventions. -->
<!-- See http://checkstyle.sf.net/config_naming.html -->
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Checks for imports -->
<!-- See http://checkstyle.sf.net/config_import.html -->
<module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports">
<property name="processJavadoc" value="false"/>
</module>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="LineLength"/>
<module name="MethodLength"/>
<module name="ParameterNumber"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="EmptyForIteratorPad"/>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!-- Modifier Checks -->
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Checks for blocks. You know, those {}'s -->
<!-- See http://checkstyle.sf.net/config_blocks.html -->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="RightCurly"/>
<!-- Checks for common coding problems -->
<!-- See http://checkstyle.sf.net/config_coding.html -->
<module name="AvoidInlineConditionals"/>
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="HiddenField"/>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<module name="MagicNumber"/>
<module name="MissingSwitchDefault"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See http://checkstyle.sf.net/config_design.html -->
<module name="DesignForExtension"/>
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<module name="VisibilityModifier"/>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="ArrayTypeStyle"/>
<module name="FinalParameters"/>
<module name="TodoComment"/>
<module name="UpperEll"/>
</module>
</module>
<?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>
......@@ -6,11 +6,6 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/webapp">
<attributes>
<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"/>
......
# web.server module - Web server providing a REST API to domain data
......@@ -50,6 +50,26 @@
<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>
......