From 8b3d7f9a4c8f4f5f47972ab95d40287f4dbde3db Mon Sep 17 00:00:00 2001 From: Christian Siegel Date: Mon, 17 Jan 2022 14:37:54 +0100 Subject: [PATCH 1/5] added support for task state handling --- README.md | 5 ++ pom.xml | 2 +- .../org/vaadin/flow/helper/AsyncManager.java | 53 ++++++++++++++++++- .../org/vaadin/flow/helper/AsyncTask.java | 5 +- .../java/org/vaadin/flow/helper/SyncTask.java | 3 ++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d51090f..8277189 100755 --- a/README.md +++ b/README.md @@ -85,6 +85,11 @@ AsyncManager.getInstance().setExceptionHandler((task, exception) -> ...); Note: By default all worker threads are started by `ThreadPoolExecutor` which defaults to pool size of 25 threads. You can change that with `AsyncManager.getInstance().setExecutorService()`. +As of version 1.2 it is possible to set a task state handler if you need more information about each task, e.g. for ui loading indicator handling. +```java +AsyncManager.getInstance().setTaskStateHandler((task, state) -> ...); +``` + ## Installing with Maven ```xml diff --git a/pom.xml b/pom.xml index 6120fbf..b503d93 100755 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.vaadin.helper async-manager - 1.1.0 + 1.2.0 Async Manager Async Manager for Vaadin Flow diff --git a/src/main/java/org/vaadin/flow/helper/AsyncManager.java b/src/main/java/org/vaadin/flow/helper/AsyncManager.java index e8e7d29..d7f8522 100644 --- a/src/main/java/org/vaadin/flow/helper/AsyncManager.java +++ b/src/main/java/org/vaadin/flow/helper/AsyncManager.java @@ -5,7 +5,10 @@ import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.UI; -import java.util.*; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -60,6 +63,11 @@ public final class AsyncManager { * Exception handler */ private ExceptionHandler exceptionHandler = AsyncManager::logException; + /** + * Task state handler + */ + private TaskStateHandler taskStateHandler; + /** * Instance of {@link ExecutorService} used for asynchronous tasks */ @@ -132,6 +140,15 @@ public void setExceptionHandler(ExceptionHandler handler) { exceptionHandler = handler; } + /** + * Set custom task state handler to monitor + * @param handler State handler to set + */ + public void setTaskStateHandler(TaskStateHandler handler) { + taskStateHandler = handler; + } + + /** * Get a {@link ExecutorService} used for asynchronous task execution. * @@ -294,6 +311,12 @@ void handleException(Task task, Exception e) { exceptionHandler.handle(task, e); } + void handleTaskStateChanged(Task task, TaskStateHandler.State state) { + if (taskStateHandler != null) { + taskStateHandler.taskChanged(task, state); + } + } + /** * Functional interface for exception handling */ @@ -307,4 +330,32 @@ public interface ExceptionHandler { */ void handle(Task task, Exception e); } + + /** + * Functional interface for task state handling + */ + @FunctionalInterface + public interface TaskStateHandler { + enum State { + /** + * Task started + */ + RUNNING, + /** + * Task done + */ + DONE, + /** + * Task was canceled + */ + CANCELED + } + + /** + * Handle state change during task execution. + * @param task Task where state change happened + * @param state State of the given task + */ + void taskChanged(Task task, State state); + } } \ No newline at end of file diff --git a/src/main/java/org/vaadin/flow/helper/AsyncTask.java b/src/main/java/org/vaadin/flow/helper/AsyncTask.java index 58965f1..1f1f5f6 100644 --- a/src/main/java/org/vaadin/flow/helper/AsyncTask.java +++ b/src/main/java/org/vaadin/flow/helper/AsyncTask.java @@ -50,7 +50,7 @@ public class AsyncTask extends Task { * Number of poll events happened while action is executing, or {@link #PUSH_ACTIVE} if * push is used for current task */ - private AtomicInteger missedPolls = new AtomicInteger(); + private final AtomicInteger missedPolls = new AtomicInteger(); /** * {@code true}, if thread may be interrupted if UI/Component detaches */ @@ -100,6 +100,7 @@ public void cancel() { if (!task.isCancelled() && !task.isDone()) { task.cancel(mayInterrupt); } + getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.CANCELED); remove(); } @@ -191,6 +192,7 @@ private void registerPoll(Component component, Action action) { private FutureTask createFutureTask(Action action) { return new FutureTask<>(() -> { try { + getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.RUNNING); action.run(this); } catch (UIDetachedException ignore) { // Do not report @@ -201,6 +203,7 @@ private FutureTask createFutureTask(Action action) { // Dump getAsyncManager().handleException(this, e); } finally { + getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.DONE); remove(); } }, this); diff --git a/src/main/java/org/vaadin/flow/helper/SyncTask.java b/src/main/java/org/vaadin/flow/helper/SyncTask.java index af0dfb6..cba0f49 100644 --- a/src/main/java/org/vaadin/flow/helper/SyncTask.java +++ b/src/main/java/org/vaadin/flow/helper/SyncTask.java @@ -69,10 +69,13 @@ public void preventThreadInterrupt() { void register(UI ui, Component component, Action action) { setUI(ui); try { + getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.RUNNING); action.run(this); + getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.DONE); } catch (Exception e) { // Dump getAsyncManager().handleException(this, e); + getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.DONE); } } } From 2dbb576177a5c079f7d3d48d856fa5afb3cd5edd Mon Sep 17 00:00:00 2001 From: Christian Siegel Date: Wed, 26 Jan 2022 14:57:30 +0100 Subject: [PATCH 2/5] - artifact-id renamed (until pull request is done) - github workflow "build" added --- .github/workflows/build.yml | 26 ++++++++++++++++++++++++++ pom.xml | 4 ++-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6b69e07 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Release build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'zulu' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml diff --git a/pom.xml b/pom.xml index b503d93..f885ff0 100755 --- a/pom.xml +++ b/pom.xml @@ -3,11 +3,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.vaadin.helper + de.csi.vaadin.helper async-manager 1.2.0 Async Manager - Async Manager for Vaadin Flow + Async Manager for Vaadin Flow (CSI fork) 10.0.5 From 264bd2db78a8e4bd8ddf7af81b69224a8f6ae010 Mon Sep 17 00:00:00 2001 From: Christian Siegel Date: Wed, 26 Jan 2022 15:25:23 +0100 Subject: [PATCH 3/5] build und publish --- .github/workflows/build-and-publish.yml | 35 +++++++++++++++++++++++++ .github/workflows/build.yml | 26 ------------------ pom.xml | 7 +++++ 3 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/build-and-publish.yml delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml new file mode 100644 index 0000000..a93bac3 --- /dev/null +++ b/.github/workflows/build-and-publish.yml @@ -0,0 +1,35 @@ +# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created +# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path + +name: Build and publish + +on: + release: + types: [created] + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'zulu' + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + # settings-path: ${{ github.workspace }} # location for the settings.xml file + + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Publish to GitHub Packages Apache Maven + # run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml + run: mvn --batch-mode deploy + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 6b69e07..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Release build - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 8 - uses: actions/setup-java@v2 - with: - java-version: '8' - distribution: 'zulu' - cache: maven - - name: Build with Maven - run: mvn -B package --file pom.xml diff --git a/pom.xml b/pom.xml index f885ff0..13fd4c7 100755 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,13 @@ + + + github + GitHub Packages + https://maven.pkg.github.com/c-si/async-manager + + From 50accaf465e064d1c480668e513690f9e1178504 Mon Sep 17 00:00:00 2001 From: Christian Siegel Date: Wed, 26 Jan 2022 15:30:34 +0100 Subject: [PATCH 4/5] =?UTF-8?q?"on=20trigger"=20ge=C3=A4ndert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-and-publish.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index a93bac3..dc89ac2 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -4,8 +4,11 @@ name: Build and publish on: - release: - types: [created] + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] jobs: build: From a6a9732fd49c5f5d7619fa86733ac8efef8c89c9 Mon Sep 17 00:00:00 2001 From: Christian Siegel Date: Mon, 7 Feb 2022 16:36:26 +0100 Subject: [PATCH 5/5] =?UTF-8?q?VaadinSession=20+=20SecurityContext=20f?= =?UTF-8?q?=C3=BCr=20Task-Thread=20setzen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++++ pom.xml | 14 +++++++++++++- .../java/org/vaadin/flow/helper/AsyncTask.java | 9 +++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8277189..4c4ac4a 100755 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ # Async Manager for Vaadin Flow +# Hinweis "c-si" Version +Bei der Ausführung der Async-Tasks werden die Session und der SecurityContext der jeweiligen UI an den "Background-Thread" gesetzt. + +# About + In complex application quite often you end up having a view that takes ages to load because some parts of view require heavy computation. If you are pursuing the goal of making your application responsive, you would probably want to defer updates for diff --git a/pom.xml b/pom.xml index 13fd4c7..2b34c15 100755 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ de.csi.vaadin.helper async-manager - 1.2.0 + 1.2.1 Async Manager Async Manager for Vaadin Flow (CSI fork) @@ -62,6 +62,18 @@ com.vaadin vaadin-core + + javax.servlet + servlet-api + 2.5 + provided + + + org.springframework.security + spring-security-web + 5.5.3 + provided + org.slf4j slf4j-simple diff --git a/src/main/java/org/vaadin/flow/helper/AsyncTask.java b/src/main/java/org/vaadin/flow/helper/AsyncTask.java index 1f1f5f6..fc5bf73 100644 --- a/src/main/java/org/vaadin/flow/helper/AsyncTask.java +++ b/src/main/java/org/vaadin/flow/helper/AsyncTask.java @@ -3,8 +3,12 @@ import com.vaadin.flow.component.*; import com.vaadin.flow.router.BeforeLeaveEvent; import com.vaadin.flow.server.Command; +import com.vaadin.flow.server.VaadinSession; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.shared.communication.PushMode; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; @@ -193,6 +197,11 @@ private FutureTask createFutureTask(Action action) { return new FutureTask<>(() -> { try { getAsyncManager().handleTaskStateChanged(this, AsyncManager.TaskStateHandler.State.RUNNING); + + // Session + Security für den Async-Task setzen + VaadinSession.setCurrent(getUI().getSession()); + SecurityContextHolder.setContext((SecurityContext) VaadinSession.getCurrent().getSession().getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)); + action.run(this); } catch (UIDetachedException ignore) { // Do not report