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();