Skip to content

Commit

Permalink
Changed the types in the Routing. (#23)
Browse files Browse the repository at this point in the history
* Changed the types in the Routing. In most cases these are still compatible because utility methods are used.

Before:
Route: Request => FXFuture[Response]
Now:
Route: Request => Response
Response: FXFuture[ResponseResult]

This made the API more easy to use by hiding complexity which is only needed in rare cases.

* Changed the types in the Routing. In most cases these are still compatible because utility methods are used.

Before:
Route: Request => FXFuture[Response]
Now:
Route: Request => Response
Response: FXFuture[ResponseResult]

This made the API more easy to use by hiding complexity which is only needed in rare cases.

* fixed unit-tests

* fixed unit-tests
  • Loading branch information
FlorianKirmaier authored Dec 18, 2023
1 parent cbe7e6a commit 9a7e98f
Show file tree
Hide file tree
Showing 25 changed files with 155 additions and 148 deletions.
17 changes: 13 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
### 0.2.8

#### Changes
* Changed the types in the Routing. In most cases these are still compatible because utility methods are used.

Before:
Route: Request => FXFuture[Response]
Now:
Route: Request => Response
Response: FXFuture[ResponseResult]

This made the API more easy to use by hiding complexity which is only needed in rare cases.
* Fixed parts of the `Route.when` api, which had unexpected argument types.
* Removed `ResponseUtils.redirect` and replaced it with `Response.redirect` and also added `Response.fromNode`

#### Improvements
* Updated JPro to version `2023.3.3`.
* Added `login` example for JPro Auth modules. This example shows how to use the JPro Auth modules to authenticate
Expand All @@ -10,10 +23,6 @@
capabilities during the authentication process. Simultaneously, `jpro-auth` module was renamed to `jpro-auth-core`
and everything under `one.jpro.platform.auth` package was moved to `one.jpro.platform.auth.core` package.

#### Changes
* Fixed parts of the `Route.when` api, which had unexpected argument types.
* Removed `ResponseUtils.redirect` and replaced it with `Response.redirect` and also added `Response.fromNode`

### 0.2.7 (December 8, 2023)

#### Improvements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ public Route createRoute() {
.filter(DevFilter.create())
.filter(OAuth2Filter.create(googleAuthProvider, googleCredentials, user -> {
setUser(user);
return Response.redirectFuture("/user/signed-in");
}, error -> Response.fromNodeFuture(new ErrorPage(error))));
return Response.redirect("/user/signed-in");
}, error -> Response.node(new ErrorPage(error))));
}

public final User getUser() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import one.jpro.platform.auth.routing.OAuth2Filter;
import one.jpro.platform.routing.Filter;
import one.jpro.platform.routing.Redirect;
import one.jpro.platform.routing.Response;
import one.jpro.platform.routing.Route;
import one.jpro.platform.routing.dev.DevFilter;
import one.jpro.platform.routing.dev.StatisticsFilter;
Expand Down Expand Up @@ -109,10 +110,10 @@ private Filter oauth2Filter(OAuth2AuthenticationProvider authProvider, OAuth2Cre
return OAuth2Filter.create(authProvider, credentials, user -> {
setUser(user);
setAuthProvider(authProvider);
return FXFuture.unit(new Redirect(USER_CONSOLE_PATH));
return Response.redirect(USER_CONSOLE_PATH);
}, error -> {
setError(error);
return FXFuture.unit(new Redirect(AUTH_ERROR_PATH));
return Response.redirect(AUTH_ERROR_PATH);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ static Filter create(JWTAuthenticationProvider authProvider,

return (route) -> (request) -> {
if (request.path().equals(authPath)) {
return FXFuture.fromJava(authProvider.token(tokenPath, credentials)
return Response.fromFuture(FXFuture.fromJava(authProvider.token(tokenPath, credentials)
.thenCompose(authProvider::authenticate))
.flatMap(userFunction::apply)
.flatExceptionally(errorFunction::apply);
.flatExceptionally(errorFunction::apply));
} else {
return route.apply(request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ public interface OAuth2Filter {
*/
static Filter create(OAuth2AuthenticationProvider authProvider,
OAuth2Credentials credentials,
Function<User, FXFuture<Response>> userFunction,
Function<Throwable, FXFuture<Response>> errorFunction) {
Function<User, Response> userFunction,
Function<Throwable, Response> errorFunction) {
Objects.requireNonNull(authProvider, "auth provider can not be null");
Objects.requireNonNull(credentials, "credentials can not be null");
Objects.requireNonNull(userFunction, "user function can not be null");
Objects.requireNonNull(errorFunction, "error function cannot be null");

return (route) -> (request) -> {
if (request.path().equals(credentials.getRedirectUri())) {
return FXFuture.fromJava(authProvider.authenticate(credentials))
.flatMap(userFunction::apply)
.flatExceptionally(errorFunction::apply);
return new Response(FXFuture.fromJava(authProvider.authenticate(credentials))
.flatMap(r -> userFunction.apply(r).future())
.flatExceptionally(r -> errorFunction.apply(r).future()));
} else {
return route.apply(request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class TestAppCrawler {
def testCrawlApp(): Unit = {
def app = new RouteNode(null) {
setRoute(Route.empty()
.and(RouteUtils.get("/", r => new Page1))
.and(RouteUtils.get("/page2", r => new Page2)))
.and(RouteUtils.getView("/", r => new Page1))
.and(RouteUtils.getView("/page2", r => new Page2)))
}
val result = AppCrawler.crawlApp("http://localhost", () => app)

Expand All @@ -50,7 +50,7 @@ class TestAppCrawler {
def testEmptyImage(): Unit = {
def app = new RouteNode(null) {
setRoute(Route.empty()
.and(RouteUtils.get("/", r => new View {
.and(RouteUtils.getView("/", r => new View {
override def title: String = ""

override def description: String = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class TestMemoryTester {
def simpleTest(): Unit = {
def app = new RouteNode(null) {
setRoute(Route.empty()
.and(get("/", r => new Page1))
.and(get("/page2", r => new Page2))
.and(get("/page4", r => new Page2)))
.and(getView("/", r => new Page1))
.and(getView("/page2", r => new Page2))
.and(getView("/page4", r => new Page2)))
}
val result = AppCrawler.crawlApp("http://localhost", () => app)
MemoryTester.testForLeaks(result, () => app)
Expand All @@ -27,9 +27,9 @@ class TestMemoryTester {
val page2 = new Page2
def app = new RouteNode(null) {
setRoute(Route.empty()
.and(get("/", r => new Page1))
.and(get("/page2", r => page2))
.and(get("/page4", r => new Page2)))
.and(getView("/", r => new Page1))
.and(getView("/page2", r => page2))
.and(getView("/page4", r => new Page2)))
}
val result = AppCrawler.crawlApp("http://localhost", () => app)
intercept[Throwable](MemoryTester.testForLeaks(result, () => app))
Expand All @@ -41,9 +41,9 @@ class TestMemoryTester {

def app = new RouteNode(null) {
setRoute(Route.empty()
.and(get("/", r => new Page1))
.and(get("/page2", r => viewFromNode(node2)))
.and(get("/page4", r => new Page2)))
.and(getView("/", r => new Page1))
.and(getView("/page2", r => viewFromNode(node2)))
.and(getView("/page4", r => new Page2)))
}

val result = AppCrawler.crawlApp("http://localhost", () => app)
Expand All @@ -54,9 +54,9 @@ class TestMemoryTester {
def simpleFailingTest3(): Unit = {
val app = inFX(new RouteNode(null) {
setRoute(Route.empty()
.and(get("/", r => new Page1))
.and(get("/page2", r => new Page2))
.and(get("/page4", r => new Page2)))
.and(getView("/", r => new Page1))
.and(getView("/page2", r => new Page2))
.and(getView("/page4", r => new Page2)))
})
val result = AppCrawler.crawlApp("http://localhost", () => app)
intercept[Throwable](MemoryTester.testForLeaks(result, () => app)) // fails because the webapp is not collectable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package one.jpro.platform.routing.crawl

import one.jpro.platform.routing.RouteUtils._
import one.jpro.platform.routing.crawl.TestUtils._
import one.jpro.platform.routing.{Redirect, Route, RouteNode}
import one.jpro.platform.routing.{Redirect, Response, Route, RouteNode}
import org.junit.jupiter.api.Test
import simplefx.experimental._

Expand All @@ -11,10 +11,10 @@ class TestSitemapGenerator {
def test(): Unit = {
def app = new RouteNode(null) {
setRoute(Route.empty()
.and(get("/", r => new Page1))
.and(get("/page2", r => new Page2))
.and(get("/page4", r => new Page2))
.and(r => FXFuture.unit(new Page1)))
.and(getView("/", r => new Page1))
.and(getView("/page2", r => new Page2))
.and(getView("/page4", r => new Page2))
.and(r => Response.view(new Page1)))
}
val result = AppCrawler.crawlApp("http://localhost", () => app)
val sm = SitemapGenerator.createSitemap("http://localhost", result)
Expand All @@ -28,8 +28,8 @@ class TestSitemapGenerator {
def testMailToRedirect(): Unit = {
def app = new RouteNode(null) {
setRoute(Route.empty()
.and(get("/", r => pageWithLink(List("/page2", "/page3", "mailto:something"))))
.and(get("/page2", r => new Redirect("mailto:something-2"))))
.and(getView("/", r => pageWithLink(List("/page2", "/page3", "mailto:something"))))
.and(get("/page2", r => Response.redirect("mailto:something-2"))))
}
val result = AppCrawler.crawlApp("http://localhost", () => app)
println("got result: " + result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import simplefx.all
object Filters {
def FullscreenFilter(fullscreenValue: Boolean): Filter = { route => { request =>
val r = route.apply(request)
if(r == null) null
else r.map {

Response(r.future.map {
case x: View =>
new View {
override def title: String = x.title
Expand All @@ -16,7 +16,7 @@ object Filters {
override def fullscreen: Boolean = fullscreenValue
}
case x => x
}
})
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package one.jpro.platform.routing

case class Redirect(to: String) extends Response
case class Redirect(to: String) extends ResponseResult
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package one.jpro.platform.routing

import simplefx.experimental.FXFuture

trait Response
case class Response(future: FXFuture[ResponseResult]) {
assert(future != null, "future must not be null - but it's value can be null")
}
object Response {
def empty(): Response = null
def emptyFuture(): FXFuture[Response] = FXFuture.unit(empty())
def redirect(to: String): Response = Redirect(to)
def redirectFuture(to: String): FXFuture[Response] = FXFuture.unit(Redirect(to))
def fromNode(node: javafx.scene.Node): Response = new Response {
RouteUtils.viewFromNode(node)
}
def fromNodeFuture(node: javafx.scene.Node): FXFuture[Response] = FXFuture.unit(fromNode(node))
def empty(): Response = Response(FXFuture.unit(null))
def redirect(to: String): Response = Response(FXFuture.unit(Redirect(to)))

def view(view: View): Response = Response(FXFuture.unit(view))
def node(node: javafx.scene.Node): Response = Response(FXFuture.unit(View.fromNode(node)))
def fromFuture(future: FXFuture[Response]): Response = Response(future.flatMap(_.future))
def fromFutureResult(future: FXFuture[ResponseResult]): Response = Response(future)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package one.jpro.platform.routing

trait ResponseResult
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,35 @@ import java.util.function.Predicate


object Route {
def empty(): Route = (r) => null
def empty(): Route = (r) => Response.empty()
}
@FunctionalInterface
trait Route {
def apply(r: Request): FXFuture[Response]
def apply(r: Request): Response

def and(x: Route): Route = { request =>
val r = apply(request)
if(r == null) {
x.apply(request)
} else {
r.flatMap{ r =>
if(r == null) {
val r = x.apply(request)
if(r == null) {
FXFuture.unit(null)
} else {
r
}
} else FXFuture.unit(r)
}
}
assert(r != null, "Route returned null: " + this + " for " + request)
Response(r.future.flatMap{ r =>
if(r == null) {
val r2 = x.apply(request)
r2.future
} else FXFuture.unit(r)
})
}
def domain(domain: String, route: Route): Route = and((r: Request) => {
if(r.domain == domain) {
route.apply(r)
} else {
null
Response.empty()
}
})
def path(path: String, route: Route): Route = and((r: Request) => {
if(r.path.startsWith(path + "/")) {
val r2 = r.copy(path = r.path.drop(path.length), directory = r.resolve(path))
route.apply(r2)
} else {
null
Response.empty()
}
})
def filter(filter: Filter): Route = filter(this)
Expand All @@ -54,25 +47,28 @@ trait Route {
}
def filterWhenFuture(cond: Predicate[Request], filter: (Request) => FXFuture[Filter]): Route = { r =>
if(cond.test(r)) {
filter(r).flatMap(filter => filter(this).apply(r))
Response(filter(r).flatMap(filter => filter(this).apply(r).future))
} else {
this.apply(r)
}
}
def when(cond: Predicate[Request], _then: Route): Route = and(r => {
val condResult = cond.test(r)
val r2: FXFuture[Response] = if(condResult) _then(r) else null
r2
if(condResult) _then(r) else Response.empty()
})
def when(cond: Predicate[Request], _then: Route, _else: Route): Route = and(r => {
if(cond.test(r)) _then(r) else _else(r)
})

def whenFuture(cond: java.util.function.Function[Request, FXFuture[java.lang.Boolean]], _then: Route): Route = and(r => {
cond.apply(r).flatMap(condResult => if (condResult) _then(r) else null)
Response.fromFuture(
cond.apply(r).map(condResult => if (condResult) _then(r) else Response.empty())
)
})

def whenFuture(cond: java.util.function.Function[Request, FXFuture[java.lang.Boolean]], _then: Route, _else: Route): Route = and(r => {
cond.apply(r).flatMap(condResult => if (condResult) _then(r) else _else(r))
Response.fromFuture(
cond.apply(r).map(condResult => if (condResult) _then(r) else _else(r))
)
})
}
Loading

0 comments on commit 9a7e98f

Please sign in to comment.