diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6253df3..1131f20 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17' - name: compile run: | - ./gradlew clean multifilehandler:assemble filehandler:assemble html-jpro:assemble popups:jar native-scrolling:assemble \ No newline at end of file + ./gradlew clean jar \ No newline at end of file diff --git a/.github/workflows/linux17.yml b/.github/workflows/linux17.yml deleted file mode 100644 index 0427dff..0000000 --- a/.github/workflows/linux17.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Linux build - -on: [push] - -jobs: - builds: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '17' - - name: compile - run: | - ./gradlew clean multifilehandler:assemble filehandler:assemble html-jpro:assemble popups:jar native-scrolling:assemble \ No newline at end of file diff --git a/README.md b/README.md index 28f2774..6d8331a 100644 --- a/README.md +++ b/README.md @@ -5,28 +5,25 @@ This project contains multiple samples for [jpro, which enables javafx in the web.](https://www.jpro.one/) - Samples: - Sample | description | Demo - -------|---------------------------------------------------------------------------------------------------------------------------------------------|------- - popups | Shows how to use popups with JPro. | [link](https://www.jfx-ensemble.com/sample/jpro-samples/PopupsApp) - multifilehandler | Shows how to upload and download mltiple files. | --- - filehandler | Shows how to upload and download files. | [link](https://www.jfx-ensemble.com/sample/jpro-samples/FileHandlerApp) - html-jpro | A small sample, which shows how to use the WebAPI to communicate between JPro and a html-site. | --- - native-scrolling | A small sample on how to use native scrolling. | --- - website | A minimalistic website with multiple pages. It uses our library [jpro-web](https://github.com/Sandec/jpro-web) | --- - auth0 | Login with [Auth0](https://auth0.com/). Read the [readme](https://github.com/JPro-one/JPro-Samples/tree/master/auth0) for more details. | --- - suneditor | Example on how to integrate a html richtext editor - [suneditor]() in this case. | [link](https://www.jfx-ensemble.com/sample/jpro-samples/JPro_Suneditor) - gps | Shows how to retrieve gps location and use it to show a map. | [link](https://www.jfx-ensemble.co/sample/jpro-samples/JPro_GeoLocation) - pwa | Install your Website as a desktop/mobile app! Read the [readme](https://github.com/JPro-one/JPro-Samples/tree/master/pwa) for more details. - - +| Sample | description | Demo | +|------------------|---------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| +| popups | Shows how to use popups with JPro. | [link](https://www.jfx-ensemble.com/sample/jpro-samples/PopupsApp) | +| multifilehandler | Shows how to upload and download mltiple files. | --- | +| filehandler | Shows how to upload and download files. | [link](https://www.jfx-ensemble.com/sample/jpro-samples/FileHandlerApp) | +| html-jpro | A small sample, which shows how to use the WebAPI to communicate between JPro and a html-site. | --- | +| native-scrolling | A small sample on how to use native scrolling. | --- | +| website | A minimalistic website with multiple pages. It uses our library [jpro-web](https://github.com/Sandec/jpro-web) | --- | +| auth0 | Login with [Auth0](https://auth0.com/). Read the [readme](https://github.com/JPro-one/JPro-Samples/tree/master/auth0) for more details. | --- | +| logging | Shows how to configure logging via `jpro.onJVMStartup`, `jpro.onFXStartup` and `jpro.onJVMShutdown` configuration options. | --- | +| suneditor | Example on how to integrate a html richtext editor - [suneditor]() in this case. | [link](https://www.jfx-ensemble.com/sample/jpro-samples/JPro_Suneditor) | +| gps | Shows how to retrieve gps location and use it to show a map. | [link](https://www.jfx-ensemble.co/sample/jpro-samples/JPro_GeoLocation) | +| pwa | Install your Website as a desktop/mobile app! Read the [readme](https://github.com/JPro-one/JPro-Samples/tree/master/pwa) for more details. | | # How to start # - ``` ./gradlew popups:jproRun ./gradlew multifilehandler:jproRun @@ -37,6 +34,7 @@ Samples: ./gradlew auth0:jproRun # Read the Readme: https://github.com/JPro-one/JPro-Samples/tree/master/auth0 ./gradlew suneditor:run ./gradlew gps:run +./gradlew logging:jproRun ``` diff --git a/auth0/src/main/java/com/jpro/samples/auth0/Auth0App.java b/auth0/src/main/java/com/jpro/samples/auth0/Auth0App.java index 87afcf9..99fc760 100644 --- a/auth0/src/main/java/com/jpro/samples/auth0/Auth0App.java +++ b/auth0/src/main/java/com/jpro/samples/auth0/Auth0App.java @@ -7,6 +7,7 @@ import javafx.stage.Stage; public class Auth0App extends WebApp { + public Auth0App(Stage stage) { super(stage); diff --git a/auth0/src/main/java/com/jpro/samples/auth0/Auth0Starter.java b/auth0/src/main/java/com/jpro/samples/auth0/Auth0Starter.java index e8245b0..5947192 100644 --- a/auth0/src/main/java/com/jpro/samples/auth0/Auth0Starter.java +++ b/auth0/src/main/java/com/jpro/samples/auth0/Auth0Starter.java @@ -8,14 +8,14 @@ public class Auth0Starter extends Application { @Override - public void start(Stage primaryStage) throws Exception { + public void start(Stage primaryStage) { Auth0App app = new Auth0App(primaryStage); app.start(SessionManager.getDefault(app, primaryStage)); primaryStage.setScene(new Scene(app)); primaryStage.show(); } - public static void main(String args[]) { + public static void main(String[] args) { launch(args); } } diff --git a/auth0/src/main/java/com/jpro/samples/auth0/auth/AuthUtil.java b/auth0/src/main/java/com/jpro/samples/auth0/auth/AuthUtil.java index d24807a..de98131 100644 --- a/auth0/src/main/java/com/jpro/samples/auth0/auth/AuthUtil.java +++ b/auth0/src/main/java/com/jpro/samples/auth0/auth/AuthUtil.java @@ -1,8 +1,6 @@ package com.jpro.samples.auth0.auth; import com.auth0.client.auth.AuthAPI; -import com.auth0.jwk.JwkProvider; -import com.auth0.jwk.JwkProviderBuilder; public class AuthUtil { static String CLIENT_ID = "???"; @@ -12,8 +10,7 @@ public class AuthUtil { AuthAPI client; public AuthUtil() { - JwkProvider jwkProvider = new JwkProviderBuilder(DOMAIN).build(); - client = new AuthAPI(DOMAIN, CLIENT_ID, CLIENT_SECRET); + client = AuthAPI.newBuilder(DOMAIN, CLIENT_ID, CLIENT_SECRET).build(); } public String authURL() { diff --git a/ensemble/site/build.gradle b/ensemble/site/build.gradle index 7aa231a..63fdc5f 100644 --- a/ensemble/site/build.gradle +++ b/ensemble/site/build.gradle @@ -15,7 +15,7 @@ buildscript { } repositories { - jcenter() + mavenCentral() } apply plugin: 'ensemble' diff --git a/logging/.gitignore b/logging/.gitignore new file mode 100644 index 0000000..b63da45 --- /dev/null +++ b/logging/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/logging/build.gradle.kts b/logging/build.gradle.kts new file mode 100644 index 0000000..884776d --- /dev/null +++ b/logging/build.gradle.kts @@ -0,0 +1,45 @@ +plugins { + application + id("org.openjfx.javafxplugin") + id("jpro-gradle-plugin") +} + +group = "one.jpro.samples" +version = "0.0.1" + +repositories { + mavenCentral() +} + +val JAVAFX_VERSION = properties["JAVAFX_VERSION"] as String +val SLF4J_VERSION = properties["SLF4J_VERSION"] as String +val LOGBACK_VERSION = properties["LOGBACK_VERSION"] as String +val JUNIT_VERSION = properties["JUNIT_VERSION"] as String + +javafx { + version = JAVAFX_VERSION + modules = listOf("javafx.graphics", "javafx.controls", "javafx.fxml", "javafx.media", "javafx.web") +} + +dependencies { + implementation("org.slf4j:slf4j-api:$SLF4J_VERSION") + implementation("org.slf4j:jul-to-slf4j:$SLF4J_VERSION") + implementation("ch.qos.logback:logback-classic:$LOGBACK_VERSION") + + testImplementation(platform("org.junit:junit-bom:$JUNIT_VERSION")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +application { + mainModule.set("one.jpro.samples.logging") + // Define the main class for the application. + mainClass.set("one.jpro.samples.logging.SampleApp") +} + +jpro { + port = 8080 +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/logging/src/main/java/module-info.java b/logging/src/main/java/module-info.java new file mode 100644 index 0000000..774ce35 --- /dev/null +++ b/logging/src/main/java/module-info.java @@ -0,0 +1,15 @@ +/** + * Module descriptor. + * + * @author Besmir Beqiri + */ +module one.jpro.samples.logging { + requires javafx.controls; + requires java.logging; + requires org.slf4j; + requires jul.to.slf4j; + requires ch.qos.logback.core; + requires ch.qos.logback.classic; + + exports one.jpro.samples.logging; +} \ No newline at end of file diff --git a/logging/src/main/java/one/jpro/samples/logging/LogOnFXStartup.java b/logging/src/main/java/one/jpro/samples/logging/LogOnFXStartup.java new file mode 100644 index 0000000..7951654 --- /dev/null +++ b/logging/src/main/java/one/jpro/samples/logging/LogOnFXStartup.java @@ -0,0 +1,18 @@ +package one.jpro.samples.logging; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Log config on FX startup. + * + * @author Besmir Beqiri + */ +public class LogOnFXStartup { + + private static final Logger logger = Logger.getLogger(LogOnFXStartup.class.getName()); + + public static void main(String[] args) { + logger.log(Level.INFO, "Some logging on JavaFX Application Startup!"); + } +} diff --git a/logging/src/main/java/one/jpro/samples/logging/LogOnJVMShutdown.java b/logging/src/main/java/one/jpro/samples/logging/LogOnJVMShutdown.java new file mode 100644 index 0000000..0c2ba88 --- /dev/null +++ b/logging/src/main/java/one/jpro/samples/logging/LogOnJVMShutdown.java @@ -0,0 +1,26 @@ +package one.jpro.samples.logging; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This is a simple class that will be executed on JVM startup. + * + * @author Besmir Beqiri + */ +public class LogOnJVMShutdown { + + private static final Logger jullogger = Logger.getLogger(LogOnJVMShutdown.class.getName()); + + public static void main(String[] args) { + + jullogger.log(Level.INFO, "JUL Logging on JVM Shutdown!"); + + for (java.util.logging.Handler handler : Logger.getLogger("").getHandlers()) { + handler.flush(); + } + LogOnJVMStartup.julShutdownTrigger.complete(null); + LogOnJVMStartup.loggerContext.stop(); + + } +} \ No newline at end of file diff --git a/logging/src/main/java/one/jpro/samples/logging/LogOnJVMStartup.java b/logging/src/main/java/one/jpro/samples/logging/LogOnJVMStartup.java new file mode 100644 index 0000000..c515d52 --- /dev/null +++ b/logging/src/main/java/one/jpro/samples/logging/LogOnJVMStartup.java @@ -0,0 +1,99 @@ +package one.jpro.samples.logging; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.joran.spi.JoranException; +import org.slf4j.LoggerFactory; +import org.slf4j.bridge.SLF4JBridgeHandler; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.logging.*; + +/** + * This is a simple class that will be executed on JVM startup. + * + * @author Besmir Beqiri + */ +public class LogOnJVMStartup { + public static LoggerContext loggerContext = null; + private static final Logger logger = Logger.getLogger(LogOnJVMStartup.class.getName()); + + public static void main(String[] args) { + // redirect j.u.l. logging to SLF4J + SLF4JBridgeHandler.removeHandlersForRootLogger(); + + String logbackFile = LogOnJVMStartup.class.getResource("/logback-sample.xml").getFile(); + loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + loggerContext.reset(); + JoranConfigurator configurator = new JoranConfigurator(); + configurator.setContext(loggerContext); + + SLF4JBridgeHandler.install(); + try { + configurator.doConfigure(logbackFile); + } catch (JoranException je) { + je.printStackTrace(); + throw new RuntimeException(je.getMessage()); + } + + synchronizeJULShutdown(); + + logger.log(Level.INFO, "Logging on JVM Startup!"); + } + + public static void synchronizeJULShutdown() { + // For reference: https://stackoverflow.com/questions/60687511/why-is-the-new-java-logger-failing-to-work-consistently-here + Logger root = Logger.getLogger(""); + Handler[] handlers = root.getHandlers(); + + for(Handler h : handlers) { + root.removeHandler(h); + } + + root.addHandler(new CleanerJoin()); + + for(Handler h : handlers) { + root.addHandler(h); + } + } + + + public static CompletableFuture julShutdownTrigger = new CompletableFuture<>(); + static class CleanerJoin extends Handler { + + CleanerJoin() { + } + + @Override + public void close() { + boolean interrupted = false; + try { + for(;;) { + try { //Could use LogManager to lookup timeout values and use a timed join. + julShutdownTrigger.get(); + break; + } catch (ExecutionException e) { + reportError("Shutdown hook failed.", e, ErrorManager.CLOSE_FAILURE); + break; + } catch (InterruptedException retry) { + interrupted = true; + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } + + @Override + public void flush() { + } + + @Override + public void publish(LogRecord r) { + isLoggable(r); + } + } +} diff --git a/logging/src/main/java/one/jpro/samples/logging/SampleApp.java b/logging/src/main/java/one/jpro/samples/logging/SampleApp.java new file mode 100644 index 0000000..959cda0 --- /dev/null +++ b/logging/src/main/java/one/jpro/samples/logging/SampleApp.java @@ -0,0 +1,34 @@ +package one.jpro.samples.logging; + +import javafx.application.Application; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.text.Font; +import javafx.stage.Stage; + +/** + * Example application for custom logging configuration. + * + * @author Besmir Beqiri + */ +public class SampleApp extends Application { + + @Override + public void start(Stage stage) { + Label label = new Label("Hello JPro!"); + label.setFont(new Font(50)); + label.setAlignment(Pos.CENTER); + stage.setScene(new Scene(label)); + stage.show(); + } + + /** + * Application entry point. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + launch(args); + } +} diff --git a/logging/src/main/resources/jpro.conf b/logging/src/main/resources/jpro.conf new file mode 100644 index 0000000..4a4751d --- /dev/null +++ b/logging/src/main/resources/jpro.conf @@ -0,0 +1,6 @@ +jpro.logConsole=false +jpro.logToJUL=true +jpro.forceShutdown = false +jpro.onJVMStartup=one.jpro.samples.logging.LogOnJVMStartup +jpro.onJVMShutdown=one.jpro.samples.logging.LogOnJVMShutdown +jpro.onFXStartup=one.jpro.samples.logging.LogOnFXStartup diff --git a/logging/src/main/resources/logback-sample.xml b/logging/src/main/resources/logback-sample.xml new file mode 100644 index 0000000..9eda0ba --- /dev/null +++ b/logging/src/main/resources/logback-sample.xml @@ -0,0 +1,24 @@ + + + + + [onJVMStartup] %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + logs/testFile.log + true + true + + [onJVMStartup] %-4relative [%thread] %-5level %logger{35} -%kvp- %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/pwa/src/main/java/com/jpro/samples/pwa/PWAApp.java b/pwa/src/main/java/com/jpro/samples/pwa/PWAApp.java index 52211bc..09af131 100644 --- a/pwa/src/main/java/com/jpro/samples/pwa/PWAApp.java +++ b/pwa/src/main/java/com/jpro/samples/pwa/PWAApp.java @@ -13,7 +13,6 @@ public class PWAApp extends Application { @Override public void start(Stage primaryStage) { - CSSFX.start(); PWAUtil pwa = new PWAUtil(primaryStage); VBox pin = new VBox(); VBox info = new VBox(); @@ -22,9 +21,7 @@ public void start(Stage primaryStage) { pin.getChildren().add(info); Button installButton = new Button("Install as PWA"); - installButton.onActionProperty().set((e) -> { - pwa.installPWA(); - }); + installButton.onActionProperty().set((e) -> pwa.installPWA()); Scene scene = new Scene(new StackPane(pin)); scene.getStylesheets().add("/com/jpro/samples/pwa/app.css"); @@ -44,5 +41,7 @@ public void start(Stage primaryStage) { info.getChildren().add(new Label("Your browser doesn't support PWA!")); } }); + + CSSFX.start(); } } diff --git a/pwa/src/main/java/com/jpro/samples/pwa/PWAUtil.java b/pwa/src/main/java/com/jpro/samples/pwa/PWAUtil.java index 5ccd17b..38cbe3e 100644 --- a/pwa/src/main/java/com/jpro/samples/pwa/PWAUtil.java +++ b/pwa/src/main/java/com/jpro/samples/pwa/PWAUtil.java @@ -3,15 +3,14 @@ import com.jpro.webapi.WebAPI; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.control.Label; import javafx.stage.Stage; import java.util.Optional; public class PWAUtil { - private WebAPI webapi; - private ObjectProperty> isInstalledProperty = new SimpleObjectProperty(Optional.empty()); + private final WebAPI webapi; + private final ObjectProperty> isInstalledProperty = new SimpleObjectProperty(Optional.empty()); public PWAUtil(Stage stage) { this(WebAPI.getWebAPI(stage)); diff --git a/settings.gradle b/settings.gradle index 7932c6b..28fd0a3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,3 +27,4 @@ include "ensemble:site" include "auth0" include "suneditor" include "gps" +include 'logging' diff --git a/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditor.java b/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditor.java index 85e11e6..8d228a9 100644 --- a/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditor.java +++ b/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditor.java @@ -9,6 +9,8 @@ import javafx.scene.layout.StackPane; import org.json.JSONTokener; +import java.util.Objects; + public class SunEditor extends StackPane { diff --git a/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditorSample.java b/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditorSample.java index cad6879..e6ea74a 100644 --- a/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditorSample.java +++ b/suneditor/src/main/java/com/jpro/samples/suneditor/SunEditorSample.java @@ -12,8 +12,7 @@ public class SunEditorSample extends Application { @Override - public void start(Stage stage) throws Exception { - CSSFX.start(); + public void start(Stage stage) { Label title = new Label("Suneditor:"); title.getStyleClass().add("title"); SunEditor sunEditor = new SunEditor(); @@ -26,5 +25,7 @@ public void start(Stage stage) throws Exception { root.getStylesheets().add(getClass().getResource("/com/jpro/samples/suneditor/css/suneditor.css").toString()); stage.setScene(scene); stage.show(); + + CSSFX.start(); } }