diff --git a/core/pom.xml b/core/pom.xml index 04cd3a1..794c9f5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ org.dorest org.dorest - 0.0.0-SNAPSHOT + 0.0.1-SNAPSHOT org.dorest.core diff --git a/core/src/main/scala/org/dorest/server/DoRestApp.scala b/core/src/main/scala/org/dorest/server/DoRestApp.scala index 95c41d8..6ec2dbb 100644 --- a/core/src/main/scala/org/dorest/server/DoRestApp.scala +++ b/core/src/main/scala/org/dorest/server/DoRestApp.scala @@ -17,19 +17,20 @@ package org.dorest.server import collection.mutable.Buffer -/** Enables the registration of [[org.dorest.server.HandlerFactory]] objects. - * - * This trait is implemented by DoRest servers. - * - * @author Michael Eichberg - */ +/** + * Enables the registration of [[org.dorest.server.HandlerFactory]] objects. + * + * This trait is to be implemented by DoRest servers. + * + * @author Michael Eichberg + */ trait DoRestApp { - private var _factories: Buffer[HandlerCreator] = Buffer() + private var _factories: Buffer[HandlerFactory] = Buffer() def factories = _factories - def register(handlerFactory: HandlerCreator) { + def register(handlerFactory: HandlerFactory) { _factories += handlerFactory } diff --git a/core/src/main/scala/org/dorest/server/HandlerFactory.scala b/core/src/main/scala/org/dorest/server/HandlerFactory.scala index 634ab66..896988e 100644 --- a/core/src/main/scala/org/dorest/server/HandlerFactory.scala +++ b/core/src/main/scala/org/dorest/server/HandlerFactory.scala @@ -17,229 +17,19 @@ package org.dorest.server import java.lang.Long -/** HandlerCreators are responsible for matching URIs and – if the URI matches – to create a new Handler - * that will then handle the request. - * - * '''Thread Safety''' - * Handler factories have to be thread safe. I.e., handler factories have to support the simultaneous - * matching of URIs; the DoRest framework use a single Handler factory for matching URIs. - * - * @author Michael Eichberg - */ -trait HandlerCreator { +/** + * HandlerCreators are responsible for matching URIs and – if the URI matches – to create a new Handler + * that will then handle the request. + * + * '''Thread Safety''' + * Handler factories have to be thread safe. I.e., handler factories have to support the simultaneous + * matching of URIs; the DoRest framework use a single Handler factory for matching URIs. + * + * @author Michael Eichberg + */ +trait HandlerFactory { def matchURI(path: String, query: String): Option[Handler] } -/** @author Michael Eichberg - */ -abstract class HandlerFactory[T <: Handler] extends HandlerCreator { - - protected implicit def namedSegmentToPathSegment(name: String): Named = new Named(name) - - /** A function that does nothing. - */ - // Used to avoid that we have to deal with Option objects or have to deal with null values. - final def DoNothing(t: T): Unit = { - /*do nothing*/ - } - - // TODO merge path and pathelement; i.e., make pathelement itself a list - /** The (URI) path of this resource. - */ - trait PathMatcher { - - /** Prepends the given path element to this path and returns a new path object. - */ - def ::(p: PathElement): PathMatcher - - /** Tries to match the path. If the path matches, a list of functions is returned which - * will then be called; e.g., to complete the initialization of the resource's parameters. - */ - def matchSegment(path: String): Option[List[(T) ⇒ Unit]] - } - - class ComplexPath(val pe: PathElement, val tail: PathMatcher) extends PathMatcher { - - def ::(pe: PathElement): PathMatcher = new ComplexPath(pe, this) - - def matchSegment(path: String): Option[List[(T) ⇒ Unit]] = { - pe.matchSegment(path) match { - case Some((pathRest, f)) ⇒ { - // this segment matched, but what about the rest of the path? - tail.matchSegment(pathRest) map (fs ⇒ f :: fs) - } - case _ ⇒ None - } - } - } - - object EmptyPath extends PathMatcher { - - def ::(p: PathElement): PathMatcher = new ComplexPath(p, this) - - def matchSegment(path: String): Option[List[(T) ⇒ Unit]] = - if (path.size == 0) Some(Nil) else None - } - - trait PathElement { - - /** Constructs a new path that consists of the given path element and this element. - */ - def ::(ps: PathElement): PathMatcher = { - new ComplexPath(ps, new ComplexPath(this, EmptyPath)) - } - - /** Tries to match a maximum length segment of the given path. If the match is successful - * the rest of the path and a function is returned that – if the whole path can be matched – - * is called. - * - * The primary purpose of the function is to enable the initialization of a resource's variable - * path parameters. - */ - def matchSegment(path: String): Option[(String, (T) ⇒ Unit)] - - } - - /** Can be used to match a path (segment) that is optional and which extends until the end of a given - * concrete path. - * - * If the given path is not empty and does not match the match is considered to have failed - * unless {link #failOnMatchError} is set to false. - * - * Cannot be used to match an optional sub-part of a path. E.g., matching something like - * {{{"/user"::{"/"userid}::"/tag"}}} where {{{"/"userid"}}} is optional is not possible. - */ - class Optional(val p: PathMatcher, val failOnMatchError: Boolean) extends PathElement { - - def matchSegment(path: String): Option[(String, (T) ⇒ Unit)] = { - if (path.size == 0) { - return Some(("", DoNothing)) - } - - p.matchSegment(path) match { - case Some(fs) ⇒ Some(("", (t: T) ⇒ { - fs.foreach(_(t)) - })) - case _ ⇒ if (failOnMatchError) None else Some(("", DoNothing)) - } - } - - } - - object Optional { - def apply(pe: PathElement, failOnMatchError: Boolean = true) = { - new Optional(new ComplexPath(pe, EmptyPath), failOnMatchError) - } - } - - /** Matches a segment that defines a long value. - */ - class LongValue(val set: Long ⇒ T ⇒ Unit) extends PathElement { - - def matchSegment(path: String): Option[(String, (T) ⇒ Unit)] = { - LongValue.matcher.findFirstIn(path).map(s ⇒ { - (path.substring(s.length), set(s.toLong)) - } - ) - } - } - - object LongValue { - - private val matcher = """^-?\d+""".r - - def apply(set: Long ⇒ T ⇒ Unit): PathElement = new LongValue(set) - - def apply(set: (T, Long) ⇒ Unit): PathElement = apply((v: Long) ⇒ (t: T) ⇒ set(t, v.toLong)) - - } - - /** Matches a string segment that contains a word character or "@". - */ - class StringValue(set: String ⇒ T ⇒ Unit) extends PathElement { - - def matchSegment(path: String): Option[(String, (T) ⇒ Unit)] = { - StringValue.matcher.findFirstIn(path).map((s) ⇒ { - (path.substring(s.length), set(s)) - } - ) - } - } - - object StringValue { - - private val matcher = """^(\w|@|-|\.)+""".r - - def apply(set: (String) ⇒ (T) ⇒ Unit) = new StringValue(set) - - def apply(set: (T, String) ⇒ Unit): PathElement = apply((v: String) ⇒ (t: T) ⇒ set(t, v)) - - } - - class AnyPath(set: String ⇒ T ⇒ Unit) extends PathElement { - def matchSegment(path: String): Option[(String, T ⇒ Unit)] = { - Some("" /* The (empty) rest of the path. */ , set(path)) - } - } - - object AnyPath { - def apply(set: (String) ⇒ (T) ⇒ Unit) = new AnyPath(set) - } - - class Named(val name: String) extends PathElement { - - def matchSegment(path: String): Option[(String, (T) ⇒ Unit)] = { - if (path.startsWith(name)) { - val pathRest = path.substring(name.length) - Some((pathRest, DoNothing)) - } - else { - None - } - } - } - - def matchURI(path: String, query: String): Option[T] = { - pathMatcher matchSegment (path) map { create(_) } - /*this.pathMatcher.matchSegment(path) match { - case Some(fs) ⇒ { - Some(create(fs)) - } - case _ ⇒ None - }*/ - } - - private def create(fs: List[(T) ⇒ Unit]): T = { - val t = create() - fs.foreach(_(t)) - t - } - - trait QueryMatcher - - object NoQuery extends QueryMatcher - - private var pathMatcher: PathMatcher = EmptyPath - - def path(f: ⇒ PathMatcher) { - pathMatcher = f - } - - def path(staticPath: String) { - path { - staticPath :: EmptyPath - } - } - - private[this] var queryMatcher: QueryMatcher = NoQuery - - def query(f: ⇒ QueryMatcher) { - queryMatcher = f - } - - /** Creates a new handler object that will be further initialized using the segments extracted by the path matchers. - */ - def create(): T -} diff --git a/core/src/main/scala/org/dorest/server/MappedDirectory.scala b/core/src/main/scala/org/dorest/server/MappedDirectory.scala index a4ded02..99aa0f5 100644 --- a/core/src/main/scala/org/dorest/server/MappedDirectory.scala +++ b/core/src/main/scala/org/dorest/server/MappedDirectory.scala @@ -23,13 +23,11 @@ import java.lang.Boolean * * @author Michael Eichberg (mail at michael-eichberg.de) */ -class MappedDirectory(val baseDirectory: String, enableIndexHTMLDeliveryOnDirectoryAccess: Boolean = false) extends Handler { +class MappedDirectory(val baseDirectory: String, val path: String, enableIndexHTMLDeliveryOnDirectoryAccess: Boolean = false) extends Handler { import java.io._ - var path: String = _ - - def processRequest(requestBody: => InputStream): Response = { + def processRequest(requestBody: ⇒ InputStream): Response = { if (method != GET) { return new SupportedMethodsResponse(GET) } @@ -53,7 +51,7 @@ class MappedDirectory(val baseDirectory: String, enableIndexHTMLDeliveryOnDirect val fileName = file.getName val fileType = { val fileSuffix = fileName.substring(fileName.lastIndexOf('.') + 1) - Some(( + Some((// TODO move to some extensible table fileSuffix match { case "css" ⇒ MediaType.TEXT_CSS case "javascript" ⇒ MediaType.APPLICATION_JAVASCRIPT @@ -87,20 +85,10 @@ class MappedDirectory(val baseDirectory: String, enableIndexHTMLDeliveryOnDirect def length = file.length.asInstanceOf[Int] def write(responseBody: OutputStream) { - // TODO Read blocks and not just single bytes. - // TODO Think about caching files. - /*val in = new FileInputStream(file) - try { - while (in.available > 0) - responseBody.write(in.read) - } finally { - if (in != null) - in.close - }*/ responseBody.write(readFully(file)) } - def readFully(file: File) : Array[Byte] = { + def readFully(file: File): Array[Byte] = { val in = new FileInputStream(file) try { val length = file.length.asInstanceOf[Int]; diff --git a/core/src/main/scala/org/dorest/server/jdk/Demo.scala b/core/src/main/scala/org/dorest/server/jdk/Demo.scala index c2e22e4..b26fe93 100644 --- a/core/src/main/scala/org/dorest/server/jdk/Demo.scala +++ b/core/src/main/scala/org/dorest/server/jdk/Demo.scala @@ -36,25 +36,25 @@ class Time } get returns HTML { - "The current (server) time is: "+new java.util.Date().toString+"" + "The current (server) time is: " + new java.util.Date().toString + "" } get returns XML { } } +object Time extends Time with PerformanceMonitor -class User extends RESTInterface with TEXTSupport { - - var user: String = _ +class User(var user: String) extends RESTInterface with TEXTSupport { get returns TEXT { - "Welcome "+user + "Welcome " + user } } -/** Implementation of a very primitive, thread-safe key-value store. - */ +/** + * Implementation of a very primitive, thread-safe key-value store. + */ object KVStore { private val ds = new scala.collection.mutable.HashMap[Long, String]() @@ -112,7 +112,7 @@ class Keys extends RESTInterface with XMLSupport { // convenience method: Location(URI) // Alternatively, it is possible to directly set the response headers // using the corresponding response headers data structure. - Location(new URL("http://"+InetAddress.getLocalHost.getHostName+":9000/keys/"+id.toString)) // TODO enable to specify the relative path + Location(new URL("http://" + InetAddress.getLocalHost.getHostName + ":9009/keys/" + id.toString)) // TODO enable to specify the relative path // the "response body" { value } @@ -120,17 +120,14 @@ class Keys extends RESTInterface with XMLSupport { } -class Key extends RESTInterface with XMLSupport { - - var id: Long = _ +class Key(val id: Long) extends RESTInterface with XMLSupport { get returns XML { KVStore.synchronized { if (!KVStore.contains(id)) { responseCode = 404 // 404 = NOT FOUND None // EMPTY BODY - } - else { + } else { val value = KVStore(id) { value } } @@ -142,8 +139,7 @@ class Key extends RESTInterface with XMLSupport { if (!KVStore.contains(id)) { responseCode = 404 // NOT FOUND None - } - else { + } else { KVStore.updated(id, XMLRequestBody.text) { XMLRequestBody.text } } @@ -156,95 +152,55 @@ class Key extends RESTInterface with XMLSupport { } -object Key { - - def setId(key: Key, id: Long) { - key.id = id - } -} - -class MonitoredMappedDirectory(baseDirectory: String) - extends MappedDirectory(baseDirectory) +class MonitoredMappedDirectory(baseDirectory: String, path: String, enableIndexHTMLDeliveryOnDirectoryAccess: Boolean = false) + extends MappedDirectory(baseDirectory, path, enableIndexHTMLDeliveryOnDirectoryAccess) with ConsoleLogging // TODO needs to exchanged with PerformanceMonitor class Demo -/** To test the restful web serice you can use, e.g., curl. For example, to - * add a value to the simple key-value store you can use: - * - * curl -v -X POST -d "Test" -H content-type:application/xml http://localhost:9009/keys - * curl http://localhost:9009/keys - */ +/** + * To test the restful web serice you can use, e.g., curl. For example, to + * add a value to the simple key-value store you can use: + * + * curl -v -X POST -d "Test" -H content-type:application/xml http://localhost:9009/keys + * curl http://localhost:9009/keys + */ object Demo extends JDKServer(9009) with scala.App with ConsoleLogging // TODO needs to exchanged { - this register new HandlerFactory[Keys] { - path { - "/keys" - } - - def create = new Keys - } - - this register new HandlerFactory[Key] { - path { - // "/keys/" :: LongValue(v => _.id = v) - - //"/keys/" :: LongValue(Key.setId _) - //"/keys/" :: LongValue((k,l) => k.id = l) - "/keys/" :: LongValue(_.id = _) - } - - def create = new Key - } - - this register new HandlerFactory[User] { - path { - "/user/" :: StringValue(_.user = _) - } - - def create = new User with PerformanceMonitor with ConsoleLogging // TODO needs to exchanged - } - - register( - new HandlerFactory[Time] { - path { - "/time" :: EmptyPath + addPathMatcher { + / { + case "keys" ⇒ / { + case MATCHED() ⇒ new Keys + case LONG(id) ⇒ new Key(id) } - query { - NoQuery - } - - /** Reusing one instance of a resource to handle all requests requires that the resource is thread safe. - * If you are unsure, just create a new instance for each request! - * - * If your resource is not trivially thread-safe, we recommend that you do not try to make it thread safe - * and instead just create a new instance. (i.e., you don't write "lazy val" but write "def" in following.) - * - * In general, whenever you have to extract path parameters or have to process a request body or your - * object representing the resource has some kind of mutable state, it is relatively certain that you - * have to create a new instance to handle a request. - */ - lazy val create = new Time() with PerformanceMonitor - }) - - // ("timezone",StringValue(v => _.timeZone = v)) - - register( - new HandlerFactory[MappedDirectory] { - path { - "/static" :: AnyPath( - v ⇒ _.path = { - if (v startsWith "/") v else "/"+v - }) + case "user" ⇒ / { + case STRING(userId) ⇒ new User(userId) with PerformanceMonitor with ConsoleLogging } - - def create = new MonitoredMappedDirectory(System.getProperty("user.home")) - }) + case "time" ⇒ + /** + * Reusing one instance of a resource to handle all requests requires that the resource is thread safe. + * If you are unsure, just create a new instance for each request! + * + * If your resource is not trivially thread-safe, we recommend that you do not try to make it thread safe + * and instead just create a new instance. + * + * In general, whenever you have to extract path parameters or have to process a request body or your + * object representing the resource has some kind of mutable state, it is relatively certain that you + * have to create a new instance to handle a request. + */ + Time + case "static" ⇒ (path) ⇒ + if (path eq null) + None + else + Some(new MonitoredMappedDirectory(System.getProperty("user.home"), path)) + } + } // start the server start() diff --git a/core/src/main/scala/org/dorest/server/jdk/JDKServer.scala b/core/src/main/scala/org/dorest/server/jdk/JDKServer.scala index 5dba637..52f7ba7 100644 --- a/core/src/main/scala/org/dorest/server/jdk/JDKServer.scala +++ b/core/src/main/scala/org/dorest/server/jdk/JDKServer.scala @@ -16,9 +16,11 @@ package org.dorest.server package jdk +import log._ +import rest._ + import com.sun.net.httpserver._ import java.net._ -import log._ import java.util.concurrent.Executor import java.util.concurrent.Executors @@ -39,6 +41,7 @@ import java.util.concurrent.Executors class JDKServer(val port : Int,val executor : Executor = Executors.newCachedThreadPool()) extends DoRestServer with DoRestApp + with URIsMatcher { private[this] val logger = Logger(classOf[JDKServer]) diff --git a/core/src/main/scala/org/dorest/server/rest/URIsMatcher.scala b/core/src/main/scala/org/dorest/server/rest/URIsMatcher.scala index bc69454..4e71254 100644 --- a/core/src/main/scala/org/dorest/server/rest/URIsMatcher.scala +++ b/core/src/main/scala/org/dorest/server/rest/URIsMatcher.scala @@ -21,10 +21,20 @@ package rest * * @author Michael Eichberg */ -trait RESTURIsMatcher { +trait URIsMatcher { + + type PathMatcher = (String) ⇒ Option[Handler] // NEEDS TO BE PROVIDED BY THE CLASS WHERE THIS CLASS IS MIXED IN - // def register(handlerFactory: HandlerFactory[Handler]) + def register(handlerFactory: HandlerFactory): Unit + + def addPathMatcher(pathMatcher: PathMatcher) { + register(new HandlerFactory { + def matchURI(path: String, query: String): Option[Handler] = { + pathMatcher(path) + } + }) + } /** * Use ROOT to match a URI that ends with "/" and where all previous segments have been successfully @@ -71,13 +81,11 @@ trait RESTURIsMatcher { } } - type PathMatcher = (String) ⇒ Option[Handler] - case class /(matcher: PartialFunction[String, PathMatcher]) extends PathMatcher { /** * @param completePath A valid URI path (or the yet unmatched part of the URI). - * The completePath is either null or is a string that starts with a "/". + * The completePath is either null or is a string that starts with a "/". * The semantics of null is that the complete path was matched; i.e., there * is no remaining part. */ @@ -112,24 +120,6 @@ trait RESTURIsMatcher { /(matcher) } - // def addPath(pathMatcher: PathMatcher) { - // - // } - - // this addPath ( - // / { - // case ROOT() ⇒ new Handler {} - // case "lectures" ⇒ / { - // case EOL() ⇒ new Handler {} /* General information about lectures */ - // case ROOT() ⇒ new Handler {} /* The lectures */ - // case STRING(lectureId) ⇒ / { - // //case NIL ⇒ null /* General Information about the lecture */ - // case "slides" ⇒ new Handler {} - // } - // } - // case "users" ⇒ new Handler {} - // } - // ) } diff --git a/core/src/test/scala/org/dorest/server/rest/URIsMatcherTest.scala b/core/src/test/scala/org/dorest/server/rest/URIsMatcherTest.scala index 6d1504b..aece6a5 100644 --- a/core/src/test/scala/org/dorest/server/rest/URIsMatcherTest.scala +++ b/core/src/test/scala/org/dorest/server/rest/URIsMatcherTest.scala @@ -22,10 +22,12 @@ import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers /** + * Tests the matching of URIs. + * * @author Michael Eichberg */ @RunWith(classOf[JUnitRunner]) -class RESTURIsMatcherTest extends FlatSpec with ShouldMatchers { +class URIsMatcherTest extends FlatSpec with ShouldMatchers { // just some dummy handlers class DummyHandler extends Handler { @@ -42,35 +44,43 @@ class RESTURIsMatcherTest extends FlatSpec with ShouldMatchers { object GHandler extends DummyHandler case class LongHandler(l: Long) extends DummyHandler + case class PathHandler(p: String) extends DummyHandler // some URIMatcher instance - val URIMatcher = new RESTURIsMatcher {} + val URIMatcher = new URIsMatcher { + + def register(handlerFactory: HandlerFactory) { throw new Error() } + + } import URIMatcher._ - val exhaustiveMatcher = / { + val exhaustiveMatcher = / { case "" ⇒ AHandler case "lectures" ⇒ BHandler case "users" ⇒ / { - case MATCHED() ⇒ CHandler - case ROOT() ⇒ DHandler + case MATCHED() ⇒ CHandler + case ROOT() ⇒ DHandler case LONG(userId) if userId > 0 ⇒ / { case EOL() ⇒ LongHandler(userId) case ROOT() ⇒ FHandler case "comments" ⇒ GHandler } - } + case "static" ⇒ (path: String) ⇒ Some(PathHandler(path)) } "A RESTURIsMatcher" should "correctly match valid URIs" in { - exhaustiveMatcher("/") should be (Some(AHandler)) + exhaustiveMatcher("/") should be(Some(AHandler)) exhaustiveMatcher("/lectures") should be(Some(BHandler)) exhaustiveMatcher("/users") should be(Some(CHandler)) exhaustiveMatcher("/users/") should be(Some(DHandler)) exhaustiveMatcher("/users/121212") should be(Some(LongHandler(121212))) exhaustiveMatcher("/users/23233321212/") should be(Some(FHandler)) exhaustiveMatcher("/users/23233321212/comments") should be(Some(GHandler)) + exhaustiveMatcher("/static") should be(Some(PathHandler(null))) + exhaustiveMatcher("/static/") should be(Some(PathHandler("/"))) + exhaustiveMatcher("/static/index.html") should be(Some(PathHandler("/index.html"))) } it should "handle URIs that do not match without throwing exceptions" in { diff --git a/demo/HelloWorld/pom.xml b/demo/HelloWorld/pom.xml index 620d90d..2e1f8e3 100644 --- a/demo/HelloWorld/pom.xml +++ b/demo/HelloWorld/pom.xml @@ -20,7 +20,7 @@ 4.0.0 de.somegroup helloworld - 0.0.1-SNAPSHOT + 1.0.0 ${project.artifactId} @@ -56,7 +56,7 @@ org.dorest org.dorest.core - 0.0.0-SNAPSHOT + 0.0.1-SNAPSHOT @@ -69,7 +69,7 @@ junit junit - 4.8.2 + 4.10 test diff --git a/demo/HelloWorld/src/main/scala/helloworld/HelloWorldServer.scala b/demo/HelloWorld/src/main/scala/helloworld/HelloWorldServer.scala index 10f60e9..5c9ffd0 100644 --- a/demo/HelloWorld/src/main/scala/helloworld/HelloWorldServer.scala +++ b/demo/HelloWorld/src/main/scala/helloworld/HelloWorldServer.scala @@ -18,22 +18,16 @@ package helloworld import org.dorest.server.jdk.JDKServer import org.dorest.server.rest.RESTInterface import org.dorest.server.rest.TEXTSupport -import org.dorest.server.HandlerFactory -// server object -object HelloWorldServer extends JDKServer(9000) with App { +object HelloWorldServer extends JDKServer(9010) with App { - // registering the handler - this register new HandlerFactory[HelloWorldHandler] { - path { "/hello" } - def create = new HelloWorldHandler - } - - // handler - class HelloWorldHandler extends RESTInterface with TEXTSupport { - get returns TEXT { "Hello World!" } - } - - start() + this addPathMatcher { + / { + case "hello" ⇒ new RESTInterface with TEXTSupport { + get returns TEXT { "Hello World!" } + } + } + } + start() } diff --git a/demo/iSmallNotes/pom.xml b/demo/iSmallNotes/pom.xml index e2d24d2..958246c 100644 --- a/demo/iSmallNotes/pom.xml +++ b/demo/iSmallNotes/pom.xml @@ -21,13 +21,13 @@ org.dorest org.dorest.demos - 0.0.0-SNAPSHOT + 0.0.1-SNAPSHOT de.smallnotes de.smallnotes iSmallNotes - + @@ -40,7 +40,7 @@ - + org.dorest diff --git a/demo/iSmallNotes/src/main/scala/de/smallnotes/Notes.scala b/demo/iSmallNotes/src/main/scala/de/smallnotes/Notes.scala index c727f77..f2d71f9 100644 --- a/demo/iSmallNotes/src/main/scala/de/smallnotes/Notes.scala +++ b/demo/iSmallNotes/src/main/scala/de/smallnotes/Notes.scala @@ -2,16 +2,14 @@ package de.smallnotes import org.dorest.server.rest.RESTInterface import org.dorest.server.rest.representation.orgjson.ORGJSONSupport -import org.json.{JSONObject, JSONArray} +import org.json.{ JSONObject, JSONArray } -class Notes +class Notes(var tagId: Long) extends RESTInterface with SmallNotesAuthorization with JDBCTransactionProvider with ORGJSONSupport { - var t_id: Long = _ - get returns JSON { val stmt = connection.prepareStatement( """ @@ -21,7 +19,7 @@ class Notes """ ) stmt.setString(1, authenticatedUser) - stmt.setLong(2, t_id) + stmt.setLong(2, tagId) val rs = stmt.executeQuery() val ja = new JSONArray() while (rs.next()) { @@ -38,7 +36,7 @@ class Notes val call = connection.prepareCall("{call add_note(?,?,?,?)}") call.registerOutParameter(4, java.sql.Types.BIGINT) call.setString(1, authenticatedUser) - call.setLong(2, t_id) + call.setLong(2, tagId) call.setString(3, note) call.execute() val jo = new JSONObject() diff --git a/demo/iSmallNotes/src/main/scala/de/smallnotes/SmallNotesApplication.scala b/demo/iSmallNotes/src/main/scala/de/smallnotes/SmallNotesApplication.scala index db75abf..c1cbf85 100644 --- a/demo/iSmallNotes/src/main/scala/de/smallnotes/SmallNotesApplication.scala +++ b/demo/iSmallNotes/src/main/scala/de/smallnotes/SmallNotesApplication.scala @@ -1,53 +1,38 @@ package de.smallnotes -import org.dorest.server.{MappedDirectory, HandlerFactory} +import org.dorest.server.{ MappedDirectory, HandlerFactory } import org.dorest.server.jdk.JDKServer class SmallNotesApplication object SmallNotesApplication extends JDKServer(8182) with App { - this register new HandlerFactory[Notes] { - path { - "/api/tags/" :: LongValue((v) => _.t_id = v) :: "/notes" :: Optional("/") - } - - def create = new Notes - } - - this register new HandlerFactory[Tag] { - path { - "/tags/" :: LongValue((v) => _.id = v) - } - - def create = new Tag - } - - this register new HandlerFactory[Tags] { - path { - "/api/tags" - } - - def create(): Tags = new Tags + val rootWebappFolder = { + var rwf = System.getProperty("de.smallnotes.resources.webapp") + if (!(rwf eq null)) + rwf + else + "src/main/resources/webapp" } - this register new HandlerFactory[MappedDirectory] { - path { - "/webapp" :: AnyPath((v) => _.path = v) + this addPathMatcher ( + / { + case "api" ⇒ / { + case "tags" ⇒ / { + case MATCHED() ⇒ new Tags + case LONG(tagId) ⇒ / { + case "notes" ⇒ new Notes(tagId) + } + } + } + case "tags" ⇒ / { + case LONG(id) ⇒ new Tag(id) + } + case "webapp" ⇒ (path) ⇒ Some(new MappedDirectory(rootWebappFolder, path, true)) } - - def create(): MappedDirectory = new MappedDirectory({ - - val dir = System.getProperty("de.smallnotes.resources.webapp") - if (!(dir eq null)) - dir - else - "src/main/resources/webapp" - },true) - } + ) start() - } diff --git a/demo/iSmallNotes/src/main/scala/de/smallnotes/Tag.scala b/demo/iSmallNotes/src/main/scala/de/smallnotes/Tag.scala index 149276c..0d59938 100644 --- a/demo/iSmallNotes/src/main/scala/de/smallnotes/Tag.scala +++ b/demo/iSmallNotes/src/main/scala/de/smallnotes/Tag.scala @@ -3,14 +3,12 @@ package de.smallnotes import org.dorest.server.rest.RESTInterface import org.dorest.server.rest.representation.orgjson.ORGJSONSupport -class Tag +class Tag(val id: Long) extends RESTInterface with SmallNotesAuthorization with JDBCTransactionProvider with ORGJSONSupport { - var id: Long = _ - delete { // TODO model as function... delete_user_tag val stmt = connection.prepareStatement("delete from \"TAGS\" where id=?") diff --git a/demo/pom.xml b/demo/pom.xml index acad7cc..609e847 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -1,13 +1,13 @@ + 4.0.0 @@ -21,7 +11,7 @@ org.dorest org.dorest - 0.0.0-SNAPSHOT + 0.0.1-SNAPSHOT org.dorest.ext @@ -35,7 +25,6 @@ orgjson gson servlet - tiscaf client stream multipart @@ -78,11 +67,6 @@ org.dorest.ext.servlet ${project.version} - - org.dorest - org.dorest.ext.tiscaf - ${project.version} - org.dorest org.dorest.ext.client diff --git a/ext/servlet/pom.xml b/ext/servlet/pom.xml index fa26f01..d78d6c8 100644 --- a/ext/servlet/pom.xml +++ b/ext/servlet/pom.xml @@ -1,13 +1,13 @@