diff --git a/pom.xml b/pom.xml
index ded5ca434..510ada204 100644
--- a/pom.xml
+++ b/pom.xml
@@ -255,7 +255,7 @@
net.ltgt.gwt.maven
gwt-maven-plugin
- 1.0.0
+ 1.1.0
true
1.8
@@ -265,11 +265,10 @@
WebProtege.jsp
${project.build.directory}/gwt/launcherDir
-
-
- -styleDETAILED
- -port8765
-
+
+ false
+ 9
+ WARN
diff --git a/webprotege-gwt-ui-client/pom.xml b/webprotege-gwt-ui-client/pom.xml
index cad70a2a2..584e9a655 100644
--- a/webprotege-gwt-ui-client/pom.xml
+++ b/webprotege-gwt-ui-client/pom.xml
@@ -227,6 +227,10 @@
compile+runtime
${project.basedir}/src/main/module-dev.gwt.xml
target/gwt-extra
+ 0
+ true
+
+ INFO
diff --git a/webprotege-gwt-ui-client/src/main/java/edu/stanford/bmir/protege/web/client/dispatch/DispatchServiceManager.java b/webprotege-gwt-ui-client/src/main/java/edu/stanford/bmir/protege/web/client/dispatch/DispatchServiceManager.java
index 26dacb4c0..825d677c7 100644
--- a/webprotege-gwt-ui-client/src/main/java/edu/stanford/bmir/protege/web/client/dispatch/DispatchServiceManager.java
+++ b/webprotege-gwt-ui-client/src/main/java/edu/stanford/bmir/protege/web/client/dispatch/DispatchServiceManager.java
@@ -137,15 +137,15 @@ public , R extends Result> void execute(A action, final Disp
}
}
-// if(batch > 0) {
-// GWT.log("[Dispatch] Batching submitted action: " + action.getClass().getSimpleName());
-// AsyncCallbackProxy proxy = new AsyncCallbackProxy(action, callback);
-// PendingActionExecution actionExecution = PendingActionExecution.get(action, proxy);
-// pendingActionExecutions.add(actionExecution);
-// }
-// else {
+ if(batch > 0) {
+ logger.info("Batching submitted action: " + action.getClass().getSimpleName());
+ AsyncCallbackProxy proxy = new AsyncCallbackProxy(action, callback);
+ PendingActionExecution actionExecution = PendingActionExecution.get(action, proxy);
+ pendingActionExecutions.add(actionExecution);
+ }
+ else {
execAction(action, callback);
-// }
+ }
}
private void checkMakingACallForCurrentProject(ProjectId projectId) {
diff --git a/webprotege-gwt-ui-server/src/main/java/edu/stanford/bmir/protege/web/server/dispatch/DispatchServlet.java b/webprotege-gwt-ui-server/src/main/java/edu/stanford/bmir/protege/web/server/dispatch/DispatchServlet.java
index 1907f4ec9..e7dff1b5f 100644
--- a/webprotege-gwt-ui-server/src/main/java/edu/stanford/bmir/protege/web/server/dispatch/DispatchServlet.java
+++ b/webprotege-gwt-ui-server/src/main/java/edu/stanford/bmir/protege/web/server/dispatch/DispatchServlet.java
@@ -1,18 +1,26 @@
package edu.stanford.bmir.protege.web.server.dispatch;
+import com.google.common.collect.ImmutableList;
import edu.stanford.bmir.protege.web.server.app.WebProtegeRemoteServiceServlet;
-import edu.stanford.bmir.protege.web.server.logging.WebProtegeLogger;
import edu.stanford.bmir.protege.web.shared.dispatch.*;
import edu.stanford.bmir.protege.web.shared.inject.ApplicationSingleton;
import edu.stanford.bmir.protege.web.shared.permissions.PermissionDeniedException;
import edu.stanford.bmir.protege.web.shared.user.UserId;
+import org.jetbrains.annotations.NotNull;
import org.keycloak.KeycloakPrincipal;
-import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.inject.Inject;
+import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -24,14 +32,14 @@
*/
@ApplicationSingleton
public class DispatchServlet extends WebProtegeRemoteServiceServlet implements DispatchService {
+
private final static java.util.logging.Logger logger = Logger.getLogger("DispatchServiceManager");
@Nonnull
private final DispatchServiceExecutor executor;
@Inject
- public DispatchServlet(@Nonnull WebProtegeLogger logger,
- @Nonnull DispatchServiceExecutor executor) {
+ public DispatchServlet(@Nonnull DispatchServiceExecutor executor) {
this.executor = checkNotNull(executor);
}
@@ -44,9 +52,71 @@ public DispatchServiceResultContainer executeAction(Action action) throws Action
var userId = UserId.valueOf(idToken.getPreferredUsername());
var executionContext = new ExecutionContext(userId,
context.getTokenString());
- return executor.execute(action, executionContext);
+ return executeAction(action, executionContext);
+ }
+
+ private DispatchServiceResultContainer executeAction(Action action,
+ ExecutionContext executionContext) {
+ if(action instanceof BatchAction) {
+ return executeBatchAction((BatchAction) action, executionContext);
+ }
+ else {
+ return executor.execute(action, executionContext);
+ }
+ }
+
+ @NotNull
+ private DispatchServiceResultContainer executeBatchAction(BatchAction action,
+ ExecutionContext executionContext) {
+ // The results are returned in the same order as the actions. This is how results are matched
+ // up with actions
+ var individualActions = action.getActions();
+ logger.info("Executing a batch action that contains " + individualActions.size() + " individual actions");
+ var resultList = Stream.generate(() -> null)
+ .limit(individualActions.size())
+ .map(o -> (ActionExecutionResult) o)
+ .collect(Collectors.toList());
+ try {
+ var future = createCompletableFutureForBatchAction(individualActions, resultList, executionContext);
+ long t0 = System.currentTimeMillis();
+ future.get();
+ long t1 = System.currentTimeMillis();
+ logger.info("Finished execution of batch action in " + (t1 - t0) + " ms");
+ } catch (InterruptedException | ExecutionException e) {
+ logger.log(Level.SEVERE, "Error while waiting for completions", e);
+ throw new ActionExecutionException("Error: " + e.getMessage());
+ }
+ return DispatchServiceResultContainer.create(BatchResult.get(ImmutableList.copyOf(resultList)));
+ }
+
+ private CompletableFuture createCompletableFutureForBatchAction(ImmutableList> individualActions,
+ List resultList,
+ ExecutionContext executionContext) {
+ List> futures = new ArrayList<>();
+ for (int i = 0; i < individualActions.size(); i++) {
+ final int index = i;
+ var future = CompletableFuture.runAsync(() -> {
+ var innerAction = individualActions.get(index);
+ try {
+ long t0 = System.currentTimeMillis();
+ var innerResult = executeAction(innerAction, executionContext);
+ long t1 = System.currentTimeMillis();
+ logger.info(" Executed " + innerAction.getClass().getSimpleName() + " in " + (t1 - t0) + " ms");
+ var innerExecutionResult = ActionExecutionResult.get(innerResult);
+ resultList.set(index, innerExecutionResult);
+ } catch (ActionExecutionException e) {
+ resultList.add(ActionExecutionResult.get(e));
+ } catch (PermissionDeniedException e) {
+ resultList.add(ActionExecutionResult.get(e));
+ }
+ });
+ futures.add(future);
+ }
+ var cfs = futures.toArray(new CompletableFuture[0]);
+ return CompletableFuture.allOf(cfs);
}
+
@Override
public RpcWhiteList getRpcWhiteList(RpcWhiteList list) {
return new RpcWhiteList();