Skip to content

Commit

Permalink
#425#120 Rework Actionhandler/Operationhandler API
Browse files Browse the repository at this point in the history
With the DI rework #127 its no longer necessary to pass the model state object as part of the execute method. instead action/operation handlers
can simply directly inject the model state if the want to use it.  Since action & operation handlers are now client session scoped an arbitary state object can be injected and used for execution. (Part of eclipse-glsp/glsp/issues/120)

- Remove the modelstate argument from the execute() method of `ActionHandler` and `OperationHandler`
- Remove `Handler` super interface because it doesn't provide any additional value
- Add documentation for affected API.
- Introduce new `DefaultActionHandler` & `DefaultOperationHandler` that serve as replacement for the now deprecated `BasicActionHandler` & `BasicOperationHandler`
- Deprecate `BasicOperationHandler` & `BasicActionHandler` & `BasicCreateOperationHandler`
- Replace usage of `BasicActionHandler` with `DefaultActionHandler`
- Replace usage of `BasicOperationHandler'  with `DefaultActionHandler`
- Replace usage of `BasicCreateOperationhandler'  with `DefaultOperationHandler` & `DefaultCreateOperationHandler`

Fixes eclipse-glsp/glsp/issues/425
  • Loading branch information
tortmayr committed Oct 25, 2021
1 parent 7e388ab commit dec601c
Show file tree
Hide file tree
Showing 47 changed files with 568 additions and 253 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ protected ActivityNodeBuilder builder(final Optional<GPoint> point, final GModel
}

@Override
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args,
final GModelState modelState) {
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args) {
return builder(point, modelState).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ protected CategoryNodeBuilder builder(final Optional<GPoint> point, final GModel
}

@Override
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args,
final GModelState modelState) {
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args) {
return builder(point, modelState).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.eclipse.glsp.graph.GNode;
import org.eclipse.glsp.graph.GPoint;
import org.eclipse.glsp.graph.builder.impl.GLayoutOptions;
import org.eclipse.glsp.server.model.GModelState;

public class CreateDecisionNodeHandler extends CreateActivityNodeHandler {

Expand All @@ -32,8 +31,7 @@ public CreateDecisionNodeHandler() {
}

@Override
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args,
final GModelState modelState) {
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args) {
String nodeType = ModelTypes.toNodeType(getElementTypeId());
return new ActivityNodeBuilder(getElementTypeId(), nodeType) //
.layoutOptions(new GLayoutOptions().minHeight(32d).minWidth(32d)) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ protected TaskNodeBuilder builder(final Optional<GPoint> point, final GModelStat
}

@Override
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args,
final GModelState modelState) {
protected GNode createNode(final Optional<GPoint> point, final Map<String, String> args) {
return builder(point, modelState).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.eclipse.glsp.graph.GCompartment;
import org.eclipse.glsp.graph.GModelElement;
import org.eclipse.glsp.graph.GPoint;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.CreateNodeOperation;
import org.eclipse.glsp.server.operations.gmodel.CreateNodeOperationHandler;

Expand All @@ -38,8 +37,8 @@ protected Optional<GPoint> getLocation(final CreateNodeOperation operation) {
}

@Override
protected Optional<GModelElement> getContainer(final CreateNodeOperation operation, final GModelState modelState) {
Optional<GModelElement> container = super.getContainer(operation, modelState);
protected Optional<GModelElement> getContainer(final CreateNodeOperation operation) {
Optional<GModelElement> container = super.getContainer(operation);
// If the container is a Category node, find its structure compartment
Optional<GModelElement> structCompt = container.filter(Category.class::isInstance).map(Category.class::cast)
.flatMap(this::getCategoryCompartment);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
* Copyright (c) 2020-2021 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -22,15 +22,14 @@
import org.apache.log4j.Logger;
import org.eclipse.glsp.example.workflow.action.LogAction;
import org.eclipse.glsp.server.actions.Action;
import org.eclipse.glsp.server.actions.BasicActionHandler;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.actions.DefaultActionHandler;
import org.eclipse.glsp.server.types.Severity;

public class LogActionHandler extends BasicActionHandler<LogAction> {
public class LogActionHandler extends DefaultActionHandler<LogAction> {
private static Logger LOG = Logger.getLogger(LogActionHandler.class);

@Override
protected List<Action> executeAction(final LogAction action, final GModelState modelState) {
protected List<Action> executeAction(final LogAction action) {
LOG.log(toLevel(action.getSeverity()), action.getMessage());
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2020 EclipseSource and others.
* Copyright (c) 2020-2021 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -23,13 +23,12 @@
import org.eclipse.glsp.server.features.contextactions.RequestContextActions;
import org.eclipse.glsp.server.features.contextactions.RequestContextActionsHandler;
import org.eclipse.glsp.server.features.contextactions.SetContextActions;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.types.Severity;

public class WorkflowRequestContextActionsHandler extends RequestContextActionsHandler {
@Override
public List<Action> executeAction(final RequestContextActions action, final GModelState modelState) {
List<Action> actions = new ArrayList<>(super.executeAction(action, modelState));
public List<Action> executeAction(final RequestContextActions action) {
List<Action> actions = new ArrayList<>(super.executeAction(action));
actions.stream()
.filter(SetContextActions.class::isInstance)
.map(SetContextActions.class::cast)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,28 @@

import org.eclipse.glsp.server.actions.ActionDispatcher;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.BasicOperationHandler;
import org.eclipse.glsp.server.operations.DefaultOperationHandler;
import org.eclipse.glsp.server.types.GLSPServerException;

import com.google.inject.Inject;

public class ApplyTaskEditOperationHandler extends BasicOperationHandler<ApplyTaskEditOperation> {
public class ApplyTaskEditOperationHandler extends DefaultOperationHandler<ApplyTaskEditOperation> {

@Inject
private ActionDispatcher actionProcessor;
protected ActionDispatcher actionDispatcher;

@Inject
protected GModelState modelState;

@Override
protected void executeOperation(final ApplyTaskEditOperation operation, final GModelState modelState) {
protected void executeOperation(final ApplyTaskEditOperation operation) {
String text = operation.getExpression();
if (text.startsWith(TaskEditContextActionProvider.DURATION_PREFIX)) {
String durationString = text.substring(TaskEditContextActionProvider.DURATION_PREFIX.length());
actionProcessor.dispatch(new EditTaskOperation(operation.getTaskId(), "duration", durationString));
actionDispatcher.dispatch(new EditTaskOperation(operation.getTaskId(), "duration", durationString));
} else if (text.startsWith(TaskEditContextActionProvider.TYPE_PREFIX)) {
String typeString = text.substring(TaskEditContextActionProvider.TYPE_PREFIX.length());
actionProcessor.dispatch(new EditTaskOperation(operation.getTaskId(), "taskType", typeString));
actionDispatcher.dispatch(new EditTaskOperation(operation.getTaskId(), "taskType", typeString));
} else {
throw new GLSPServerException(
"Cannot process 'ApplyTaskEditOperation' expression: " + operation.getExpression());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@

import org.eclipse.glsp.example.workflow.wfgraph.TaskNode;
import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.operations.BasicOperationHandler;
import org.eclipse.glsp.server.operations.DefaultOperationHandler;
import org.eclipse.glsp.server.types.GLSPServerException;

public class EditTaskOperationHandler extends BasicOperationHandler<EditTaskOperation> {
import com.google.inject.Inject;

public class EditTaskOperationHandler extends DefaultOperationHandler<EditTaskOperation> {

@Inject
protected GModelState modelState;

@Override
protected void executeOperation(final EditTaskOperation operation, final GModelState modelState) {
protected void executeOperation(final EditTaskOperation operation) {
Optional<TaskNode> task = modelState.getIndex().findElementByClass(operation.getTaskId(), TaskNode.class);
if (task.isEmpty()) {
throw new RuntimeException("Cannot find task with id '" + operation.getTaskId() + "'");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,83 @@
import java.util.List;
import java.util.Optional;

import org.eclipse.glsp.server.model.GModelState;
import org.eclipse.glsp.server.types.Handler;

public interface ActionHandler extends Handler<Action> {
/**
* An action handler can execute certain {@link Action} types (subclasses) that are dispatched by the
* {@link ActionDispatcher}. The action handler processes the action in the {@link ActionHandler#execute(Action)}
* method and returns a list of response actions that to be dispatched.
* One action handler can handle multiple different action types.
*/
public interface ActionHandler {
/**
* Returns the list of action type (subclasses) that can be handled by this action handler.
*
* @return A list of {@link Action} classes that can be handled.
*/
List<Class<? extends Action>> getHandledActionTypes();

@Override
/**
* Validates whether the given {@link Action} can be handled by this action handler.
* The default implementation uses the list of handled action types ({@link ActionHandler#getHandledActionTypes()}
* to determine whether this handler can handle an action. Only actions that are instances of one of these types can
* be handled.
*
* @param action The action that should be validated.
* @return `true` if the given action can be handled, `false` otherwise.
*/
default boolean handles(final Action action) {
return getHandledActionTypes().stream().anyMatch(clazz -> clazz.isInstance(action));
}

/**
* Executes the action handler for the given {@link Action} and returns a list of response actions that should be
* dispatched by the {@link ActionDispatcher}. If the given action cannot be handled by this action handler an empty
* list is returned.
*
* @param action The action that should be processed.
* @return A list of response actions that should be dispatched.
*/
List<Action> execute(Action action);

/**
* Helper method to convert the given {@link Action} to a {@link List}.
*
* @param action One ore more action objects that should be converted.
* @return The given action objects as list.
*/
default List<Action> listOf(final Action... action) {
return Arrays.asList(action);
}

/**
* Helper method to convert the given {@link Optional} action to a {@link List}.
*
* @param optionalAction The optional action that should be converted.
* @return A list of the given action or an empty list if no value was present.
*/
default List<Action> listOf(final Optional<Action> optionalAction) {
List<Action> actions = new ArrayList<>();
optionalAction.ifPresent(action -> actions.add(action));
return actions;
}

List<Action> execute(Action action, GModelState modelState);

/**
* Helper method that can be used to return an empty {@link List} of {@link Action}s.
*
* @return An empty action list.
*/
default List<Action> none() {
return Collections.emptyList();
}

/**
* Returns the priority of this action handler. The priority is used to derive the execution order if multiple
* action handlers should execute the same {@link Action}. The default priority is `0` and the priority is sorted
* descending. This means handlers with a priority >0 are executed before handlers with a default priority and
* handlers with a
* priority <0 are executed afterwards.
*
* @return the priority as integer.
*/
default int getPriority() { return 0; }

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019 EclipseSource and others.
* Copyright (c) 2019-2021 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -15,45 +15,34 @@
********************************************************************************/
package org.eclipse.glsp.server.actions;

import java.util.Arrays;
import java.util.List;

import org.eclipse.glsp.server.internal.util.GenericsUtil;
import org.eclipse.glsp.server.model.GModelState;

public abstract class BasicActionHandler<T extends Action> implements ActionHandler {
protected final Class<T> actionType;
import com.google.inject.Inject;

public BasicActionHandler() {
this.actionType = deriveActionType();
}
/**
* Deprecated, will be removed after a grace period with the 1.0.0 release.
* Please use {@link DefaultActionHandler} instead and directly inject the {@link GModelState}.
*/
@Deprecated
public abstract class BasicActionHandler<T extends Action> extends DefaultActionHandler<T> {

@Inject
protected GModelState modelState;

@Override
@SuppressWarnings("unchecked")
protected Class<T> deriveActionType() {
return (Class<T>) GenericsUtil.getGenericTypeParameterClass(getClass(), BasicActionHandler.class);
}

@Override
public boolean handles(final Action action) {
return actionType.isInstance(action);
}

@Override
public List<Action> execute(final Action action, final GModelState modelState) {
if (handles(action)) {
T actualAction = actionType.cast(action);
return executeAction(actualAction, modelState);
}
return none();
public List<Action> executeAction(final T actualAction) {
return executeAction(actualAction, modelState);
}

protected abstract List<Action> executeAction(T actualAction, GModelState modelState);

public Class<T> getActionType() { return actionType; }

@Override
public List<Class<? extends Action>> getHandledActionTypes() {
return Arrays.asList(actionType);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public class ClientActionHandler implements ActionHandler {
@Inject
protected Provider<GLSPClient> client;

@Inject
protected GModelState modelState;

private final List<Class<? extends Action>> handledActionTypes;

@Inject
Expand All @@ -45,7 +48,7 @@ public ClientActionHandler(@Named(CLIENT_ACTIONS) final Set<Action> clientAction
public List<Class<? extends Action>> getHandledActionTypes() { return handledActionTypes; }

@Override
public List<Action> execute(final Action action, final GModelState modelState) {
public List<Action> execute(final Action action) {
send(modelState.getClientId(), action);
return Collections.emptyList();
}
Expand Down
Loading

0 comments on commit dec601c

Please sign in to comment.