diff --git a/gradle.properties b/gradle.properties
index 2809ca81..cba203ff 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,6 @@
JPRO_PLATFORM_VERSION = 0.5.1-SNAPSHOT
+
JPRO_VERSION = 2024.4.1
JAVAFX_BUILD_VERSION = 17.0.12
JAVAFX_EXAMPLES_VERSION = 23.0.1
diff --git a/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestAppCrawler.scala b/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestAppCrawler.scala
index 33358fca..bf86617a 100644
--- a/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestAppCrawler.scala
+++ b/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestAppCrawler.scala
@@ -33,12 +33,10 @@ class TestAppCrawler {
@Test
def testCrawlApp(): Unit = {
- def app = new RouteNode(null) {
- setRoute(Route.empty()
+ def route = Route.empty()
.and(Route.get("/", r => Response.view(new Page1)))
- .and(Route.get("/page2", r => Response.view(new Page2))))
- }
- val result = AppCrawler.crawlApp("http://localhost", () => app)
+ .and(Route.get("/page2", r => Response.view(new Page2)))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
assert(result.pages.contains("/"), result.pages)
assert(result.pages.contains("/page2"), result.pages)
@@ -48,17 +46,15 @@ class TestAppCrawler {
@Test
def testEmptyImage(): Unit = {
- def app = new RouteNode(null) {
- setRoute(Route.empty()
+ def route = Route.empty()
.and(Route.get("/", r => Response.view(new View {
override def title: String = ""
override def description: String = ""
override def content: all.Node = new ImageView(null: Image)
- }))))
- }
- val result = AppCrawler.crawlApp("http://localhost", () => app)
+ })))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
}
@Test
@@ -99,16 +95,19 @@ class TestAppCrawler {
}
@Test
- def testImageInStyle (): Unit = inFX {
- val view = new View {
+ def testImageInStyle (): Unit = {
+ def view = new View {
override def title: String = ""
override def description: String = ""
val content: Node = new Region() {
style = "-fx-background-image: url('/testfiles/test.jpg');"
}
}
- val r = AppCrawler.crawlPage(view)
- assert(r.pictures.nonEmpty)
+ val r = AppCrawler.crawlRoute("http://localhost", () =>
+ Route.empty().and(Route.get("/", r => Response.view(view)))
+ )
+ assert(r.pages.length == 1)
+ assert(r.reports.head.pictures.nonEmpty)
}
@Test
diff --git a/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestMemoryTester.scala b/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestMemoryTester.scala
index abe0552c..7748d6ce 100644
--- a/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestMemoryTester.scala
+++ b/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestMemoryTester.scala
@@ -11,53 +11,48 @@ class TestMemoryTester {
@Test
def simpleTest(): Unit = {
- def app = new RouteNode(null) {
- setRoute(Route.empty()
+ def route = Route.empty()
.and(Route.get("/", r => Response.view(new Page1)))
.and(Route.get("/page2", r => Response.view(new Page2)))
- .and(Route.get("/page4", r => Response.view(new Page2))))
- }
- val result = AppCrawler.crawlApp("http://localhost", () => app)
- MemoryTester.testForLeaks(result, () => app)
+ .and(Route.get("/page4", r => Response.view(new Page2)))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
+ MemoryTester.testForLeaks(result, () => route)
}
@Test
def simpleFailingTest(): Unit = {
val page2 = new Page2
- def app = new RouteNode(null) {
- setRoute(Route.empty()
+ def route = Route.empty()
.and(Route.get("/", r => Response.view(new Page1)))
.and(Route.get("/page2", r => Response.view(page2)))
- .and(Route.get("/page4", r => Response.view(new Page2))))
- }
- val result = AppCrawler.crawlApp("http://localhost", () => app)
- intercept[Throwable](MemoryTester.testForLeaks(result, () => app))
+ .and(Route.get("/page4", r => Response.view(new Page2)))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
+ intercept[Throwable](MemoryTester.testForLeaks(result, () => route))
}
@Test
def simpleFailingTest2(): Unit = {
var node2 = new Label()
- def app = new RouteNode(null) {
- setRoute(Route.empty()
+ def route = Route.empty()
.and(Route.get("/", r => Response.view(new Page1)))
.and(Route.get("/page2", r => Response.node(node2)))
- .and(Route.get("/page4", r => Response.view(new Page2))))
- }
+ .and(Route.get("/page4", r => Response.view(new Page2)))
- val result = AppCrawler.crawlApp("http://localhost", () => app)
- intercept[Throwable](MemoryTester.testForLeaks(result, () => app))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
+ intercept[Throwable](MemoryTester.testForLeaks(result, () => route))
}
+ /*
@Test
def simpleFailingTest3(): Unit = {
- val app = inFX(new RouteNode(null) {
- setRoute(Route.empty()
+ val route = inFX(Route.empty()
.and(Route.get("/", r => Response.view(new Page1)))
.and(Route.get("/page2", r => Response.view(new Page2)))
- .and(Route.get("/page4", r => Response.view(new Page2))))
- })
- val result = AppCrawler.crawlApp("http://localhost", () => app)
- intercept[Throwable](MemoryTester.testForLeaks(result, () => app)) // fails because the webapp is not collectable
+ .and(Route.get("/page4", r => Response.view(new Page2)))
+ )
+ val result = AppCrawler.crawlApp("http://localhost", () => route)
+ intercept[Throwable](MemoryTester.testForLeaks(result, () => route)) // fails because the webapp is not collectable
}
+ */
}
diff --git a/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestSitemapGenerator.scala b/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestSitemapGenerator.scala
index 8b3c5ff9..4fa8f2e0 100644
--- a/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestSitemapGenerator.scala
+++ b/jpro-routing/core-test/src/test/scala/one/jpro/platform/routing/crawl/TestSitemapGenerator.scala
@@ -9,29 +9,27 @@ import simplefx.experimental._
class TestSitemapGenerator {
@Test
def test(): Unit = {
- def app = new RouteNode(null) {
- setRoute(Route.empty()
+ def route = Route.empty()
.and(get("/", r => Response.view(new Page1)))
.and(get("/page2", r => Response.view(new Page2)))
.and(get("/page4", r => Response.view(new Page2)))
- .and(r => Response.view(new Page1)))
- }
- val result = AppCrawler.crawlApp("http://localhost", () => app)
+ .and(r => Response.view(new Page1))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
val sm = SitemapGenerator.createSitemap("http://localhost", result)
+ println("Crawl Report: " + result)
println("SiteMap: " + sm)
- assert(sm.contains("http://localhost/page4"))
- assert(!sm.contains("http://external/link"))
+
+ assert(sm.contains("http://localhost/page4"), "sitemap did not contain page4")
+ assert(!sm.contains("http://external/link"), "sitemap contained external link")
assert(!sm.contains("mailto"))
}
@Test
def testMailToRedirect(): Unit = {
- def app = new RouteNode(null) {
- setRoute(Route.empty()
- .and(get("/", r => Response.view(pageWithLink(List("/page2", "/page3", "mailto:something")))))
- .and(get("/page2", r => Response.redirect("mailto:something-2"))))
- }
- val result = AppCrawler.crawlApp("http://localhost", () => app)
+ def route = Route.empty()
+ .and(get("/", r => Response.view(pageWithLink(List("/page2", "/page3", "mailto:something")))))
+ .and(get("/page2", r => Response.redirect("mailto:something-2")))
+ val result = AppCrawler.crawlRoute("http://localhost", () => route)
println("got result: " + result)
val sm = SitemapGenerator.createSitemap("http://localhost", result)
println("SiteMap2: " + sm)
diff --git a/jpro-routing/core/src/main/java/module-info.java b/jpro-routing/core/src/main/java/module-info.java
index 07a1786b..e294390e 100644
--- a/jpro-routing/core/src/main/java/module-info.java
+++ b/jpro-routing/core/src/main/java/module-info.java
@@ -18,4 +18,5 @@
exports one.jpro.platform.routing.filter.container;
exports one.jpro.platform.routing.sessionmanager;
exports one.jpro.platform.routing.extensions.linkheader;
+ exports one.jpro.platform.routing.server;
}
\ No newline at end of file
diff --git a/jpro-routing/core/src/main/java/one/jpro/platform/routing/server/IgnoreMe.java b/jpro-routing/core/src/main/java/one/jpro/platform/routing/server/IgnoreMe.java
new file mode 100644
index 00000000..3ee90685
--- /dev/null
+++ b/jpro-routing/core/src/main/java/one/jpro/platform/routing/server/IgnoreMe.java
@@ -0,0 +1,7 @@
+package one.jpro.platform.routing.server;
+
+/**
+ * I only exist to allow the creation of a module-info.java file.
+ */
+public class IgnoreMe {
+}
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/LinkUtil.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/LinkUtil.scala
index 1dc7c7a8..1c23eda0 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/LinkUtil.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/LinkUtil.scala
@@ -29,7 +29,9 @@ object LinkUtil {
}
def getSessionManager(node: Node): SessionManager = {
- SessionManagerContext.getContext(node)
+ val sm = SessionManagerContext.getContext(node)
+ assert(sm != null, "SessionManager was null")
+ sm
}
def setLink(node: Node, url: String): Unit = {
@@ -86,7 +88,7 @@ object LinkUtil {
def refresh(node: Node): Unit = {
val man = LinkUtil.getSessionManager(node)
assert(man.url != null, "current url was null")
- man.gotoURL(man.url, false, true)
+ man.gotoURL(man.url, false)
}
private object LinkDesktop {
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/Request.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/Request.scala
index 2833bf22..13e3334f 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/Request.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/Request.scala
@@ -72,18 +72,28 @@ object Request {
private lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
private var wref_null = new WeakReference[Node](null)
- def fromString(x: String): Request = {
- if(!isValidLink(x)) {
- logger.warn("Warning - Invalid Link: " + x)
+
+ def fromString(s: String, oldView: Node): Request = {
+ val oldViewW = new WeakReference(oldView)
+ Request.fromString(s).copy(oldContent = oldViewW, origOldContent = oldViewW)
+ }
+ def fromString(s: String): Request = {
+ try {
+ if(!isValidLink(s)) {
+ logger.warn("Warning - Invalid Link: " + s)
+ }
+ val uri = new URI(s)
+ val rawQuery = uri.getRawQuery
+ val query: Map[String,String] = if(rawQuery == null || rawQuery == "") Map() else rawQuery.split("&").map(x => {
+ val Array(a,b) = x.split("=")
+ a -> b
+ }).toMap
+ val path = uri.getPath
+ val res = Request(s, uri.getScheme, uri.getHost, uri.getPort, path,path,"/", query,wref_null,wref_null)
+ res
+ } catch {
+ case e: Exception =>
+ throw new RuntimeException("Could not parse Request from string: " + s, e)
}
- val uri = new URI(x)
- val rawQuery = uri.getRawQuery
- val query: Map[String,String] = if(rawQuery == null || rawQuery == "") Map() else rawQuery.split("&").map(x => {
- val Array(a,b) = x.split("=")
- a -> b
- }).toMap
- val path = uri.getPath
- val res = Request(x, uri.getScheme, uri.getHost, uri.getPort, path,path,"/", query,wref_null,wref_null)
- res
}
}
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/RouteNode.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/RouteNode.scala
index 23c263fd..3840649d 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/RouteNode.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/RouteNode.scala
@@ -32,17 +32,9 @@ class RouteNode(stage: Stage, route: Route) extends StackPane { THIS =>
lazy val webAPI: WebAPI = if(WebAPI.isBrowser) com.jpro.webapi.WebAPI.getWebAPI(stage) else null
var newRoute: Route = route
- def getRoute: Route = newRoute
+ def getRoute(): Route = newRoute
def setRoute(x: Route): Unit = newRoute = x
- def route(s: String, oldView: Node) = {
- val oldViewW = new WeakReference(oldView)
- newRoute(Request.fromString(s).copy(oldContent = oldViewW, origOldContent = oldViewW))
- }
- def route = {
- (s: String) => newRoute(Request.fromString(s))
- }
-
def start(sessionManager: SessionManager) = {
SessionManagerContext.setContext(this, sessionManager)
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/View.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/View.scala
index e9fd29af..db13f1d6 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/View.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/View.scala
@@ -33,7 +33,7 @@ abstract class View extends ResponseResult { THIS =>
* @param x path
* @return whether the view handles the url change
*/
- def handleURL(x: String): Boolean = false
+ def handleRequest(x: Request): Boolean = false
def mapContent(f: Node => Node): View = new View {
override def title: String = THIS.title
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/AppCrawler.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/AppCrawler.scala
index 43ceeb29..5337740f 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/AppCrawler.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/AppCrawler.scala
@@ -1,7 +1,8 @@
package one.jpro.platform.routing.crawl
-import one.jpro.platform.routing.sessionmanager.DummySessionManager
-import one.jpro.platform.routing.{Redirect, Response, RouteNode, SessionManagerContext, View}
+import one.jpro.platform.routing.crawl.AppCrawler.{CrawlReportApp, CrawlReportPage}
+import one.jpro.platform.routing.sessionmanager.{SessionManager, SessionManagerDesktop, SessionManagerDummy}
+import one.jpro.platform.routing.{LinkUtil, Redirect, Request, Response, Route, RouteApp, RouteNode, SessionManagerContext, View}
import org.slf4j.{Logger, LoggerFactory}
import simplefx.all._
import simplefx.core._
@@ -14,6 +15,7 @@ import scala.collection.JavaConverters._
object AppCrawler {
private lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
+
case class LinkInfo(url: String, description: String)
case class ImageInfo(url: String, description: String)
@@ -22,6 +24,7 @@ object AppCrawler {
case class CrawlReportApp(pages: List[String], reports: List[CrawlReportPage], deadLinks: List[String])
+
def crawlPage(page: View): CrawlReportPage = {
var foundLinks: List[LinkInfo] = Nil
var images: List[ImageInfo] = Nil
@@ -29,14 +32,14 @@ object AppCrawler {
var visitedNodes: Set[Node] = Set()
def crawlNode(x: Node): Unit = {
- if(x == null) return
+ if (x == null) return
if (visitedNodes.contains(x)) return
visitedNodes += x
if (x.getProperties.containsKey("link")) {
val link = x.getProperties.get("link").asInstanceOf[String]
- if(link != null) {
+ if (link != null) {
var desc = x.getProperties.get("description").asInstanceOf[String]
- if(desc == null) desc = ""
+ if (desc == null) desc = ""
foundLinks ::= LinkInfo(link, desc)
}
}
@@ -52,10 +55,10 @@ object AppCrawler {
}
if (x.isInstanceOf[ListView[_]]) {
val lview = x.asInstanceOf[ListView[Any]]
- if(lview.getItems != null) {
- lview.getItems.asScala.zipWithIndex.foreach { case (item,index) =>
+ if (lview.getItems != null) {
+ lview.getItems.asScala.zipWithIndex.foreach { case (item, index) =>
val factory = lview.cellFactoryProperty().get()
- if(factory != null) {
+ if (factory != null) {
val cell: ListCell[Any] = factory.call(lview)
cell.setItem(item)
cell.updateIndex(index)
@@ -69,85 +72,54 @@ object AppCrawler {
if (x.isInstanceOf[Region]) {
val region = x.asInstanceOf[Region]
var rimages = List.empty[Image]
- if(region.border != null && region.border.getImages != null) rimages :::= region.border.getImages.asScala.map(_.getImage).toList
- if(region.background != null && region.background.getImages != null) rimages :::= region.background.getImages.asScala.map(_.getImage).toList
- rimages.foreach{ image =>
+ if (region.border != null && region.border.getImages != null) rimages :::= region.border.getImages.asScala.map(_.getImage).toList
+ if (region.background != null && region.background.getImages != null) rimages :::= region.background.getImages.asScala.map(_.getImage).toList
+ rimages.foreach { image =>
val imgURL = getImageURL(image)
- if(imgURL != null) {
- images ::= ImageInfo(imgURL,region.accessibleRoleDescription)
+ if (imgURL != null) {
+ images ::= ImageInfo(imgURL, region.accessibleRoleDescription)
}
}
}
- if(x.isInstanceOf[ImageView]) {
+ if (x.isInstanceOf[ImageView]) {
val view = x.asInstanceOf[ImageView]
- if(view.image != null) {
+ if (view.image != null) {
val url = getImageURL(view.image)
val description = view.accessibleRoleDescription
- if(url != null) {
- images ::= ImageInfo(url,description)
+ if (url != null) {
+ images ::= ImageInfo(url, description)
}
}
}
}
- val scene = new Scene(new Group())
- val content = page.realContent.asInstanceOf[Parent]
- SessionManagerContext.setContext(content, new DummySessionManager)
- scene.setRoot(content)
- page.realContent.applyCss()
+ val node = page.realContent
crawlNode(page.realContent)
CrawlReportPage(page.url, foundLinks.reverse, images.reverse, page.title, page.description)
}
- def crawlApp(prefix: String, createApp: Supplier[RouteNode]): CrawlReportApp = {
- var toIndex = Set[String]("/")
- var indexed = Set[String]()
- var redirects = Set[String]()
- var deadLinks = Set[String]()
- var reports: List[CrawlReportPage] = List()
-
- def isOwnLink(x: String): Boolean = x.startsWith(prefix) || x.startsWith("/")
- while (toIndex.nonEmpty) {
- val crawlNext = toIndex.head
- toIndex -= crawlNext
- indexed += crawlNext
- val result = inFX {
- createApp.get().route(crawlNext)
- }.future.await
- result match {
- case Redirect(url) =>
- redirects += crawlNext
- if (!indexed.contains(url) && !toIndex.contains(url)) {
- if (isOwnLink(url)) {
- toIndex += url
- }
- }
- case view: View =>
- view.url = crawlNext
- try {
- val newReport = inFX(crawlPage(view))
- reports = newReport :: reports
- def simplifyLink(x: String) = {
- if(x.startsWith(prefix)) x.drop(prefix.length) else x
- }
- newReport.links.filter(x => isOwnLink(x.url)).foreach { link =>
- val url = simplifyLink(link.url)
- if (!indexed.contains(url) && !toIndex.contains(url)) {
- toIndex += url
- }
- }
- } catch {
- case ex: Throwable =>
- logger.error(s"Error crawling page: $crawlNext", ex)
- deadLinks += crawlNext
- }
- case null =>
- deadLinks += crawlNext
- }
- }
+ def crawlRoute(prefix: String, createRoute: () => Route): CrawlReportApp = {
+ val crawler = new AppCrawler(prefix, () => {
+ val stage = new Stage
+ val routeNode = new RouteNode(stage)
+ stage.setScene(new Scene(routeNode))
+ val sm = new SessionManagerDesktop(routeNode)
+ routeNode.setRoute(createRoute())
+ routeNode.start(sm)
+ routeNode
+ })
+ crawler.crawlAll()
+ }
- CrawlReportApp((indexed -- redirects -- deadLinks).toList, reports.reverse, deadLinks.toList)
+ def routeToRouteNode(route: Route): RouteNode = {
+ val stage = new Stage
+ val routeNode = new RouteNode(stage)
+ stage.setScene(new Scene(routeNode))
+ val sm = new SessionManagerDesktop(routeNode)
+ routeNode.setRoute(route)
+ routeNode.start(sm)
+ routeNode
}
def getImageURL(x: Image): String = {
@@ -160,6 +132,11 @@ object AppCrawler {
}
}
+ def simplifyAndEncode(x: String) = encodeSlashes(simplifyURL(x))
+ def encodeSlashes(x: String): String = {
+ x.replaceAllLiterally("/1", "/11")
+ .replaceRepeatedly("//", "/1/")
+ }
private val cpTriggers = List[String]("jar!","classes", "main")
private val local = new File("").getAbsoluteFile.toURI.toURL.toString
@@ -171,11 +148,6 @@ object AppCrawler {
home -> "home://",
"jar:" + fixFile(home) -> "jar:home://",
)
- def simplifyAndEncode(x: String) = encodeSlashes(simplifyURL(x))
- def encodeSlashes(x: String): String = {
- x.replaceAllLiterally("/1", "/11")
- .replaceRepeatedly("//", "/1/")
- }
implicit class ExtStr(val x: String) extends AnyVal {
def replaceRepeatedly(oldString: String, newString: String): String = {
val r = x.replaceAllLiterally(oldString,newString)
@@ -202,3 +174,87 @@ object AppCrawler {
}
}
}
+
+class AppCrawler(prefix: String, createApp: Supplier[RouteNode]) {
+ import AppCrawler.logger
+
+ assert(!isApplicationThread, "This method must not be called on the application thread")
+ var toIndex = Set[String]("/")
+ var indexed = Set[String]()
+ var redirects = Set[String]()
+ var deadLinks = Set[String]()
+ var reports: List[CrawlReportPage] = List()
+
+ def isOwnLink(x: String): Boolean = x.startsWith(prefix) || x.startsWith("/")
+
+ def doStep(): Unit = {
+ val crawlNext = toIndex.head
+ toIndex -= crawlNext
+ indexed += crawlNext
+
+ val app: RouteNode = inFX(createApp.get())
+ val result = inFX {
+ LinkUtil.getSessionManager(app)
+ val request = Request.fromString(crawlNext)
+ app.getRoute()(Request.fromString(crawlNext))
+ }.future.await
+ result match {
+ case Redirect(url) =>
+ redirects += crawlNext
+ if (!indexed.contains(url) && !toIndex.contains(url)) {
+ if (isOwnLink(url)) {
+ toIndex += url
+ }
+ }
+ case view: View =>
+ println(s"View: ${view.url} crawlNext: $crawlNext")
+ try {
+ val newReport = inFX{
+ runScheduler{
+ LinkUtil.getSessionManager(app).gotoURL(crawlNext, view, pushState = false)
+ view.url = crawlNext
+ assert(app.scene != null, s"Scene is null for $crawlNext")
+ assert(app.scene.root != null, s"Root is null for $crawlNext")
+ }
+ app.scene.root.applyCss()
+ //app.scene.root.layout()
+ //println(SceneGraphSerializer.serialize(app.scene.root))
+ assert(view.realContent.parent != null, s"Parent is null for $crawlNext")
+ assert(view.realContent.scene != null, s"Scene is null for $crawlNext")
+ println("SCENE WH: " + view.realContent.scene.getWidth + " " + view.realContent.scene.getHeight)
+ AppCrawler.crawlPage(view)
+ }
+ reports = newReport :: reports
+ def simplifyLink(x: String) = {
+ if(x.startsWith(prefix)) x.drop(prefix.length) else x
+ }
+ newReport.links.filter(x => isOwnLink(x.url)).foreach { link =>
+ val url = simplifyLink(link.url)
+ if (!indexed.contains(url) && !toIndex.contains(url)) {
+ toIndex += url
+ }
+ }
+ } catch {
+ case ex: Throwable =>
+ logger.error(s"Error crawling page: $crawlNext", ex)
+ deadLinks += crawlNext
+ }
+ case null =>
+ deadLinks += crawlNext
+ }
+ }
+ def crawlAll(): CrawlReportApp = {
+
+ while (toIndex.nonEmpty) {
+ try {
+ doStep()
+ } catch {
+ case ex: Throwable =>
+ logger.error("Error in crawlAll", ex)
+ }
+ }
+
+ CrawlReportApp((indexed -- redirects -- deadLinks).toList, reports.reverse, deadLinks.toList)
+ }
+
+}
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/MemoryTester.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/MemoryTester.scala
index 99e62d91..035b72d8 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/MemoryTester.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/crawl/MemoryTester.scala
@@ -1,8 +1,10 @@
package one.jpro.platform.routing.crawl
import one.jpro.jmemorybuddy.JMemoryBuddy
+import javafx.stage.Stage
import one.jpro.platform.routing.crawl.AppCrawler.CrawlReportApp
-import one.jpro.platform.routing.{RouteNode, View}
+import one.jpro.platform.routing.sessionmanager.SessionManagerDesktop
+import one.jpro.platform.routing.{Request, Route, RouteApp, RouteNode, View}
import org.slf4j.{Logger, LoggerFactory}
import simplefx.cores.default.inFX
@@ -12,14 +14,24 @@ object MemoryTester {
private lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
- def testForLeaks(x: CrawlReportApp, appFactory: Supplier[RouteNode]): Unit = {
+ def testForLeaks(x: CrawlReportApp, appFactory: () => Route): Unit = {
+ testForLeaks2(x, () => {
+ val stage = new Stage
+ val routeNode = new RouteNode(stage)
+ val sm = new SessionManagerDesktop(routeNode)
+ routeNode.setRoute(appFactory())
+ routeNode.start(sm)
+ routeNode
+ })
+ }
+ def testForLeaks2(x: CrawlReportApp, appFactory: Supplier[RouteNode]): Unit = {
x.pages.foreach { pageURL =>
logger.debug(s"Checking for leak for the url: $pageURL")
JMemoryBuddy.memoryTest(checker1 => {
JMemoryBuddy.memoryTest(checker2 => {
- val factory = inFX(appFactory.get())
- assert(factory != null, "The appFactory must not return null")
- val view = inFX(appFactory.get().route(pageURL)).future.await
+ val factory: RouteNode = inFX(appFactory.get())
+ assert(factory != null, "The appFactory must not return null ")
+ val view = inFX(appFactory.get().getRoute()(Request.fromString(pageURL))).future.await
checker2.setAsReferenced(factory)
checker2.assertCollectable(view) // Hm?
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/server/RouteHTTP.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/server/RouteHTTP.scala
new file mode 100644
index 00000000..0c85d8fd
--- /dev/null
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/server/RouteHTTP.scala
@@ -0,0 +1,49 @@
+package one.jpro.platform.routing.server
+
+import com.jpro.webapi.server.{Response, ServerAPI}
+import one.jpro.platform.routing.{Route, RouteApp}
+import one.jpro.platform.routing.crawl.{AppCrawler, SitemapGenerator}
+
+object RouteHTTP {
+ var initialized = false
+
+ def main(args: Array[String]): Unit = {
+ // System.out.println("Hello, world!");
+ // val route = getRoute();
+ // CrawlReportApp report = AppCrawler.generate(route);
+ // SiteMapGenerator siteMapGenerator = new SiteMapGenerator();
+ }
+}
+
+abstract class RouteHTTP {
+
+ def start(): Unit = {
+
+ new Thread(() => {
+ val prefix = "localhost"
+
+ if(RouteHTTP.initialized) {
+ throw new IllegalStateException("RouteHTTP already initialized")
+ }
+
+ //val appCrawler = new AppCrawler(prefix, () => AppCrawler.routeToRouteNode(getRoute()))
+
+ val report = AppCrawler.crawlRoute(prefix, () => getRoute())
+
+ ServerAPI.getServerAPI().addRequestHandler(
+ r => {
+ println("RouteHTTP> request: " + r.getPath())
+ r.getPath() match {
+ case "/sitemap.xml" =>
+ Response.of(SitemapGenerator.createSitemap(prefix, report).getBytes())
+ case _ =>
+ Response.empty()
+ }
+ }
+ )
+ }).start()
+
+
+ }
+ def getRoute(): Route
+}
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManager.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManager.scala
index b3a9803e..2b9aca20 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManager.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManager.scala
@@ -4,7 +4,7 @@ import com.jpro.webapi.WebAPI
import one.jpro.jmemorybuddy.JMemoryBuddyLive
import javafx.beans.property.{ObjectProperty, SimpleObjectProperty}
import javafx.collections.{FXCollections, ObservableList}
-import one.jpro.platform.routing.{HistoryEntry, Response, ResponseResult, RouteNode, View}
+import one.jpro.platform.routing.{HistoryEntry, Request, Response, ResponseResult, RouteNode, View}
import org.slf4j.{Logger, LoggerFactory}
import simplefx.all._
import simplefx.core._
@@ -21,10 +21,6 @@ trait SessionManager { THIS =>
def webApp: RouteNode
- var ganalytics = false
- var gtags = false
- var trackingID = ""
-
val getHistoryBackward: ObservableList[HistoryEntry] = FXCollections.observableArrayList()
val currentHistoryProperty: ObjectProperty[HistoryEntry] = new SimpleObjectProperty(null)
val getHistoryForwards: ObservableList[HistoryEntry] = FXCollections.observableArrayList()
@@ -47,32 +43,32 @@ trait SessionManager { THIS =>
SessionManager.externalLinkImpl.accept(url)
}
} else {
- gotoURL(url,true,true)
+ gotoURL(url,true)
}
}
- def gotoURL(url: String, pushState: Boolean = true, track: Boolean = true): Unit = {
+ def gotoURL(url: String, pushState: Boolean = true): Unit = {
val url2 = SessionManager.mergeURLs(THIS.url, url)
try {
logger.debug(s"goto: $url")
- val newView = if(view != null && view.handleURL(url)) Response(FXFuture(view)) else {
- getView(url2)
+ val request = getRequest(url)
+ val newView = if(view != null && view.handleRequest(request)) Response(FXFuture(view)) else {
+ webApp.getRoute()(request)
}
newView.future.map { response =>
assert(response != null, s"Response for $url2 was null")
this.url = url2
- gotoURL(url2, response, pushState, track)
+ gotoURL(url2, response, pushState)
}
} catch {
case ex: Exception =>
logger.error(s"Error while loading the path $url2", ex)
}
}
+ def gotoURL(_url: String, x: ResponseResult, pushState: Boolean): Unit
- def gotoURL(_url: String, x: ResponseResult, pushState: Boolean, track: Boolean): Unit
-
- def getView(url: String): Response = {
+ def getRequest(url: String): Request = {
val node = if(view == null) null else view.realContent
- webApp.route(url, node)
+ Request.fromString(url, node)
}
def start(): Unit
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDesktop.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDesktop.scala
index 6324471c..68758542 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDesktop.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDesktop.scala
@@ -7,6 +7,7 @@ import simplefx.core._
import simplefx.util.ReflectionUtil
class SessionManagerDesktop(val webApp: RouteNode) extends SessionManager { THIS =>
+ assert(webApp != null, "webApp must not be null!")
private lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
@@ -14,7 +15,7 @@ class SessionManagerDesktop(val webApp: RouteNode) extends SessionManager { THIS
historyForward = historyCurrent :: historyForward
historyCurrent = historyBackward.head
historyBackward = historyBackward.tail
- gotoURL(historyCurrent.path, false, true)
+ gotoURL(historyCurrent.path, false)
}
def goForward(): Unit = {
@@ -22,10 +23,10 @@ class SessionManagerDesktop(val webApp: RouteNode) extends SessionManager { THIS
historyBackward = historyCurrent :: historyBackward
historyCurrent = historyForward.head
historyForward = historyForward.tail
- gotoURL(historyCurrent.path, false, true)
+ gotoURL(historyCurrent.path, false)
}
- def gotoURL(_url: String, x: ResponseResult, pushState: Boolean, track: Boolean): Unit = {
+ def gotoURL(_url: String, x: ResponseResult, pushState: Boolean): Unit = {
x match {
case Redirect(url) =>
logger.debug(s"redirect: ${_url} -> $url")
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/DummySessionManager.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDummy.scala
similarity index 60%
rename from jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/DummySessionManager.scala
rename to jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDummy.scala
index fc5776ab..84a08c5b 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/DummySessionManager.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerDummy.scala
@@ -2,16 +2,15 @@ package one.jpro.platform.routing.sessionmanager
import one.jpro.platform.routing.{Response, ResponseResult, RouteNode}
-class DummySessionManager extends SessionManager {
- override def webApp: RouteNode = null
+class SessionManagerDummy(val webApp: RouteNode) extends SessionManager {
override def goBack(): Unit = ()
override def goForward(): Unit = ()
- override def gotoURL(_url: String, x: ResponseResult, pushState: Boolean, track: Boolean): Unit = ()
+ override def gotoURL(_url: String, x: ResponseResult, pushState: Boolean): Unit = {
- override def getView(url: String): Response = Response.empty()
+ }
override def start(): Unit = ()
}
diff --git a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerWeb.scala b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerWeb.scala
index 4453ade0..6dbe8e20 100644
--- a/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerWeb.scala
+++ b/jpro-routing/core/src/main/scala/one/jpro/platform/routing/sessionmanager/SessionManagerWeb.scala
@@ -7,6 +7,7 @@ import simplefx.all._
class SessionManagerWeb(val webApp: RouteNode, val webAPI: WebAPI) extends SessionManager { THIS =>
+ assert(webApp != null, "webApp must not be null!")
private lazy val logger: Logger = LoggerFactory.getLogger(getClass.getName)
@@ -21,16 +22,18 @@ class SessionManagerWeb(val webApp: RouteNode, val webAPI: WebAPI) extends Sessi
webAPI.executeScript("history.go(1);")
}
- webAPI.addInstanceCloseListener(() => {
- // if the session only has redirects, the view is null
- if (THIS.view != null) {
- THIS.view.onClose()
- THIS.view.setSessionManager(null)
- markViewCollectable(THIS.view)
- }
- })
+ if(webAPI != null) { // somtetimes webAPI is null, for example when crawling
+ webAPI.addInstanceCloseListener(() => {
+ // if the session only has redirects, the view is null
+ if (THIS.view != null) {
+ THIS.view.onClose()
+ THIS.view.setSessionManager(null)
+ markViewCollectable(THIS.view)
+ }
+ })
+ }
- def gotoURL(_url: String, x: ResponseResult, pushState: Boolean, track: Boolean): Unit = {
+ def gotoURL(_url: String, x: ResponseResult, pushState: Boolean): Unit = {
assert(x != null, "Response was null for url: " + _url)
val url = _url
x match {
@@ -78,40 +81,20 @@ class SessionManagerWeb(val webApp: RouteNode, val webAPI: WebAPI) extends Sessi
webAPI.executeScript(s"""document.title = "${view.title.replace("\"","\\\"")}";""")
webAPI.executeScript(s"""document.querySelector('meta[name="description"]').setAttribute("content", "${view.description.replace("\"","\\\"")}");""")
webAPI.executeScript(s"history.replaceState($initialState, null, null)")
- if(ganalytics && track) {
- webAPI.executeScript(s"""
- |ga('set', {
- | page: "${view.url.replace("\"","\\\"")}",
- | title: "${view.title.replace("\"","\\\"")}"
- |});
- |
- |// send it for tracking
- |ga('send', 'pageview');
- """.stripMargin)
- }
- if(gtags && track) {
- assert(trackingID.nonEmpty)
- webAPI.executeScript(s"""
- |gtag('config', '$trackingID', {
- | 'page_title' : "${view.title.replace("\"","\\\"")}",
- | 'page_location': "${view.title.replace("\"","\\\"")}"
- |});""".stripMargin)
- }
-
}
}
- def gotoFullEncodedURL(x: String, pushState: Boolean = true, track: Boolean = true): Unit = {
+ def gotoFullEncodedURL(x: String, pushState: Boolean = true): Unit = {
// We no longer decode - we should only process proper URLs
// If the URL is not proper, we will get a warning when creating the Request.
- gotoURL(x, pushState, track)
+ gotoURL(x, pushState)
}
def start(): Unit = {
- gotoFullEncodedURL(webAPI.getBrowserURL, false, false)
+ gotoFullEncodedURL(webAPI.getBrowserURL, false)
logger.debug("registering popstate")
webAPI.registerJavaFunction("popstatejava", (s: String) => {
- gotoFullEncodedURL(s.drop(1).dropRight(1).replace("\\\"", "\""), false)
+ gotoFullEncodedURL(s.drop(1).dropRight(1).replace("\\\"", "\""))
})
webAPI.registerJavaFunction("jproGotoURL", (s: String) => {
gotoURL(s.drop(1).dropRight(1).replace("\\\"", "\""))
diff --git a/jpro-routing/example/src/main/scala/example/scala/TestWebApplication.scala b/jpro-routing/example/src/main/scala/example/scala/TestWebApplication.scala
index 09cdf1c1..cacf3c28 100644
--- a/jpro-routing/example/src/main/scala/example/scala/TestWebApplication.scala
+++ b/jpro-routing/example/src/main/scala/example/scala/TestWebApplication.scala
@@ -14,11 +14,13 @@ import simplefx.core._
import scala.collection.JavaConverters.asScalaBufferConverter
-class MyApp(stage: Stage) extends RouteNode(stage) {
+class TestWebApplication extends RouteApp {
- stylesheets ::= "test.css"
+ override def createRoute(): Route = {
+ if(getRouteNode() != null) {
+ getRouteNode().stylesheets ::= "test.css"
+ }
- setRoute(
Route.empty()
.and(get("", (r) => Response.view(new MainView)))
.and(get("/", (r) => Response.view(new MainView)))
@@ -44,11 +46,9 @@ class MyApp(stage: Stage) extends RouteNode(stage) {
.and(get("/it's\" tricky", (r) => Response.view(new MainView)))
.filter(DevFilter.create)
.filter(StatisticsFilter.create)
- )
+ }
+
- // addTransition{ case (null,view2,true ) => PageTransition.InstantTransition }
- // addTransition{ case (view,view2,true ) => PageTransition.MoveDown }
- // addTransition{ case (view,view2,false) => PageTransition.MoveUp }
}
class Header(view: View, sessionManager: SessionManager) extends HBox {
@@ -142,8 +142,8 @@ trait Page extends View { view =>
}
}
- override def handleURL(x: String): Boolean = {
- println("handleURL called: " + x)
+ override def handleRequest(x: Request): Boolean = {
+ println("handleRequest called: " + x)
return false;
}
}
@@ -368,15 +368,3 @@ class ParalaxPage extends Page {
}
-
-
-object TestWebApplication extends App
-@SimpleFXApp class TestWebApplication {
- val app = new MyApp(stage)
- if(WebAPI.isBrowser) {
- root = app
- } else {
- scene = new Scene(app, 1400,800)
- }
- app.start(SessionManager.getDefault(app,stage))
-}
diff --git a/jpro-routing/example/src/main/scala/example/scala/TestWebApplicationHTTP.scala b/jpro-routing/example/src/main/scala/example/scala/TestWebApplicationHTTP.scala
new file mode 100644
index 00000000..feda558c
--- /dev/null
+++ b/jpro-routing/example/src/main/scala/example/scala/TestWebApplicationHTTP.scala
@@ -0,0 +1,18 @@
+package example.scala
+
+import one.jpro.platform.routing.Route
+import one.jpro.platform.routing.server.RouteHTTP
+
+
+object TestWebApplicationHTTP {
+ def main(args: Array[String]): Unit = {
+ new TestWebApplicationHTTP().start()
+ }
+}
+class TestWebApplicationHTTP extends RouteHTTP {
+
+ override def getRoute: Route = {
+ new TestWebApplication().createRoute()
+ }
+
+}