Merged in plt-17-api-server-infra (pull request #30)

Jersey / Jackson / JAX-RS added to nodes
This commit is contained in:
Rick Parker 2016-03-11 10:09:23 +00:00
commit 00294e78cc
3 changed files with 89 additions and 2 deletions

View File

@ -16,7 +16,8 @@ buildscript {
ext.quasar_version = '0.7.5-SNAPSHOT'
ext.asm_version = '0.5.3'
ext.artemis_version = '1.2.0'
ext.jetty_version = '9.3.7.v20160115'
ext.jetty_version = '9.1.1.v20140108'
ext.jersey_version = '2.22.2'
repositories {
mavenCentral()
@ -99,6 +100,22 @@ dependencies {
compile "org.jolokia:jolokia-agent-war:2.0.0-M1"
compile "commons-fileupload:commons-fileupload:1.3.1"
// Jersey for JAX-RS implementation for use in Jetty
compile "org.glassfish.jersey.core:jersey-server:${jersey_version}"
compile "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}"
compile "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}"
// NOTE there is a Jackson version clash between jersey-media-json-jackson (v2.5.4) and jackson-module-kotlin (v.2.5.5)
// Have not found an Issue in the issue tracker for Jersey for this issue
compile ("org.glassfish.jersey.media:jersey-media-json-jackson:${jersey_version}") {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations'
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core'
}
compile ("com.fasterxml.jackson.module:jackson-module-kotlin:2.5.5-2") {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations'
}
compile "com.fasterxml.jackson.core:jackson-annotations:2.5.5"
// Unit testing helpers.
testCompile 'junit:junit:4.12'
testCompile 'com.google.jimfs:jimfs:1.1' // in memory java.nio filesystem.

View File

@ -0,0 +1,51 @@
package api
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.KotlinModule
import java.time.LocalDate
import javax.ws.rs.ext.ContextResolver
import javax.ws.rs.ext.Provider
/**
* Primary purpose is to install Kotlin extensions for Jackson ObjectMapper so data classes work
* and to organise serializers / deserializers for java.time.* classes as necessary
*/
@Provider
class Config: ContextResolver<ObjectMapper> {
val defaultObjectMapper = createDefaultMapper()
override fun getContext(type: java.lang.Class<*>): ObjectMapper {
return defaultObjectMapper
}
companion object {
private fun createDefaultMapper(): ObjectMapper {
val mapper = ObjectMapper()
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // Although we shouldn't really use java.util.* but instead java.time.*
val timeModule = SimpleModule("java.time")
timeModule.addSerializer(LocalDate::class.java, ToStringSerializer)
timeModule.addDeserializer(LocalDate::class.java, LocalDateDeserializer)
mapper.registerModule(timeModule)
mapper.registerModule(KotlinModule())
return mapper
}
}
object ToStringSerializer: JsonSerializer<Any>() {
override fun serialize(obj: Any, generator: JsonGenerator, provider: SerializerProvider) {
generator.writeString(obj.toString())
}
}
object LocalDateDeserializer: JsonDeserializer<LocalDate>() {
override fun deserialize(parser: JsonParser, context: DeserializationContext): LocalDate {
return LocalDate.parse(parser.text)
}
}
}

View File

@ -8,6 +8,7 @@
package core.node
import api.Config
import com.google.common.net.HostAndPort
import core.messaging.LegallyIdentifiableNode
import core.messaging.MessagingService
@ -18,6 +19,9 @@ import core.utilities.loggerFor
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.handler.HandlerCollection
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder
import org.glassfish.jersey.server.ServerProperties
import org.glassfish.jersey.servlet.ServletContainer
import org.eclipse.jetty.webapp.WebAppContext
import java.io.RandomAccessFile
import java.lang.management.ManagementFactory
@ -25,6 +29,7 @@ import java.nio.channels.FileLock
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import kotlin.reflect.KClass
class ConfigurationException(message: String) : Exception(message)
@ -73,12 +78,21 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration
})
}
// Data upload and download to services (attachments, rates oracles etc)
// API, data upload and download to services (attachments, rates oracles etc)
handlerCollection.addHandler(ServletContextHandler().apply {
contextPath = "/"
setAttribute("storage", storage)
addServlet(DataUploadServlet::class.java, "/upload/*")
addServlet(AttachmentDownloadServlet::class.java, "/attachments/*")
setAttribute("services", services)
val jerseyServlet = addServlet(ServletContainer::class.java, "/api/*")
// Give the app a slightly better name in JMX rather than a randomly generated one
jerseyServlet.setInitParameter(ServerProperties.APPLICATION_NAME, "node.api")
jerseyServlet.setInitParameter(ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED, "true")
jerseyServlet.initOrder = 0 // Initialise at server start
// Add your API provider classes (annotated for JAX-RS) here
setProviders(jerseyServlet, Config::class)
})
server.handler = handlerCollection
@ -86,6 +100,11 @@ class Node(dir: Path, val p2pAddr: HostAndPort, configuration: NodeConfiguration
return server
}
private fun setProviders(jerseyServlet: ServletHolder, vararg providerClasses: KClass<out Any>) {
val providerClassNames = providerClasses.map { it.java.canonicalName }.joinToString()
jerseyServlet.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES, providerClassNames)
}
override fun start(): Node {
alreadyRunningNodeCheck()
super.start()