/* * Copyright 2017 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.workbench.common.stunner.core.graph.command.impl; import java.util.Collection; import java.util.Optional; import org.jboss.errai.common.client.api.annotations.MapsTo; import org.jboss.errai.common.client.api.annotations.Portable; import org.kie.workbench.common.stunner.core.command.CommandResult; import org.kie.workbench.common.stunner.core.graph.Edge; import org.kie.workbench.common.stunner.core.graph.Node; import org.kie.workbench.common.stunner.core.graph.command.GraphCommandExecutionContext; import org.kie.workbench.common.stunner.core.graph.command.GraphCommandResultBuilder; import org.kie.workbench.common.stunner.core.graph.content.view.View; import org.kie.workbench.common.stunner.core.graph.content.view.ViewConnector; import org.kie.workbench.common.stunner.core.rule.RuleViolation; import org.kie.workbench.common.stunner.core.rule.context.CardinalityContext; import org.kie.workbench.common.stunner.core.rule.context.EdgeCardinalityContext; import org.kie.workbench.common.stunner.core.rule.context.impl.RuleContextBuilder; import org.uberfire.commons.validation.PortablePreconditions; /** * A Command to set the incoming connection for an edge. * Notes: * - In case <code>targetNode</code> is <code>null</code>, connector's target node, if any, will be removed. * - if connector is not view based, no need to provide magnet index. */ @Portable public final class SetConnectionTargetNodeCommand extends AbstractGraphCommand { private final String targetNodeUUID; private final String edgeUUID; private final Integer magnetIndex; private String lastTargetNodeUUID; private Integer lastMagnetIndex; private transient Edge<? extends View, Node> edge; private transient Node<? extends View<?>, Edge> sourceNode; private transient Node<? extends View<?>, Edge> targetNode; @SuppressWarnings("unchecked") public SetConnectionTargetNodeCommand(final @MapsTo("targetNodeUUID") String targetNodeUUID, final @MapsTo("edgeUUID") String edgeUUID, final @MapsTo("magnetIndex") Integer magnetIndex) { this.edgeUUID = PortablePreconditions.checkNotNull("edgeUUID", edgeUUID); this.targetNodeUUID = targetNodeUUID; this.magnetIndex = magnetIndex; this.lastTargetNodeUUID = null; this.lastMagnetIndex = null; } @SuppressWarnings("unchecked") public SetConnectionTargetNodeCommand(final Node<? extends View<?>, Edge> targetNode, final Edge<? extends View, Node> edge, final Integer magnetIndex) { this(null != targetNode ? targetNode.getUUID() : null, edge.getUUID(), magnetIndex); this.edge = PortablePreconditions.checkNotNull("edge", edge); this.sourceNode = edge.getSourceNode(); this.targetNode = targetNode; } @SuppressWarnings("unchecked") public SetConnectionTargetNodeCommand(final Node<? extends View<?>, Edge> targetNode, final Edge<? extends View, Node> edge) { this(targetNode, edge, null); } @Override @SuppressWarnings("unchecked") public CommandResult<RuleViolation> execute(final GraphCommandExecutionContext context) { final CommandResult<RuleViolation> results = allow(context); if (!results.getType().equals(CommandResult.Type.ERROR)) { final Node<?, Edge> targetNode = getTargetNode(context); final Edge<? extends View, Node> edge = getEdge(context); final Node<? extends View<?>, Edge> lastTargetNode = edge.getTargetNode(); if (null != lastTargetNode) { lastTargetNodeUUID = lastTargetNode.getUUID(); lastTargetNode.getInEdges().remove(edge); } if (null != targetNode) { targetNode.getInEdges().add(edge); } edge.setTargetNode(targetNode); if (null != magnetIndex) { ViewConnector connectionContent = (ViewConnector) edge.getContent(); lastMagnetIndex = connectionContent.getTargetMagnetIndex(); connectionContent.setTargetMagnetIndex(magnetIndex); } } return results; } @SuppressWarnings("unchecked") protected CommandResult<RuleViolation> check(final GraphCommandExecutionContext context) { final Node<? extends View<?>, Edge> targetNode = getTargetNode(context); final Edge<View<?>, Node> edge = (Edge<View<?>, Node>) getEdge(context); final GraphCommandResultBuilder resultBuilder = new GraphCommandResultBuilder(); final Collection<RuleViolation> connectionRuleViolations = doEvaluate(context, RuleContextBuilder.GraphContexts.connection(getGraph(context), edge, Optional.ofNullable(sourceNode), Optional.ofNullable(targetNode))); resultBuilder.addViolations(connectionRuleViolations); final Node<? extends View<?>, Edge> currentTarget = edge.getTargetNode(); if (null != currentTarget) { final Collection<RuleViolation> cardinalityRuleViolations = doEvaluate(context, RuleContextBuilder.GraphContexts.edgeCardinality(getGraph(context), currentTarget, edge, EdgeCardinalityContext.Direction.INCOMING, Optional.of(CardinalityContext.Operation.DELETE))); resultBuilder.addViolations(cardinalityRuleViolations); } if (null != targetNode) { final Collection<RuleViolation> cardinalityRuleViolations = doEvaluate(context, RuleContextBuilder.GraphContexts.edgeCardinality(getGraph(context), targetNode, edge, EdgeCardinalityContext.Direction.INCOMING, Optional.of(CardinalityContext.Operation.ADD))); resultBuilder.addViolations(cardinalityRuleViolations); } return resultBuilder.build(); } @Override @SuppressWarnings("unchecked") public CommandResult<RuleViolation> undo(final GraphCommandExecutionContext context) { final SetConnectionTargetNodeCommand undoCommand = new SetConnectionTargetNodeCommand((Node<? extends View<?>, Edge>) getNode(context, lastTargetNodeUUID), getEdge(context), lastMagnetIndex); return undoCommand.execute(context); } private Edge<? extends View, Node> getEdge(final GraphCommandExecutionContext context) { if (null == this.edge) { this.edge = getViewEdge(context, edgeUUID); } return this.edge; } @SuppressWarnings("unchecked") private Node<? extends View<?>, Edge> getSourceNode(final GraphCommandExecutionContext context) { if (null == sourceNode) { sourceNode = (Node<? extends View<?>, Edge>) getEdge(context).getSourceNode(); } return sourceNode; } @SuppressWarnings("unchecked") private Node<? extends View<?>, Edge> getTargetNode(final GraphCommandExecutionContext context) { if (null == targetNode) { targetNode = (Node<? extends View<?>, Edge>) getNode(context, targetNodeUUID); } return targetNode; } public Edge<? extends View, Node> getEdge() { return edge; } public Integer getMagnetIndex() { return magnetIndex; } public Node<? extends View<?>, Edge> getTargetNode() { return targetNode; } public Node<? extends View<?>, Edge> getSourceNode() { return sourceNode; } @Override public String toString() { return "SetConnectionTargetNodeCommand [edge=" + edgeUUID + ", candidate=" + (null != targetNodeUUID ? targetNodeUUID : "null") + ", magnet=" + magnetIndex + "]"; } }