package com.temenos.interaction.core.hypermedia; import java.util.Map; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import com.temenos.interaction.core.hypermedia.expression.Expression; /* * #%L * interaction-core * %% * Copyright (C) 2012 - 2013 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ public class Transition { /** * Add transition to every item in collection */ public static final int FOR_EACH = 1; /** * This transition is an auto transition.<br> * This transition will result in the target state automatically being requested following * the successful execution of the current state. */ public static final int AUTO = 2; /** * Add a subresource */ public static final int EMBEDDED = 4; /** * Add a transition used in an expression */ public static final int EXPRESSION = 8; /** * This transition is a redirect transition.<br> * A transition to this state from the same state as the auto target will result * in a 205 Reset Content HTTP status at runtime. * A transition to this state from a different state to the auto target will result * in a 303 Redirect HTTP status at runtime. */ public static final int REDIRECT = 16; /** * Add a sub resource to every item in collection */ public static final int FOR_EACH_EMBEDDED = 32; private ResourceState source, target; private ResourceLocator locator; private final TransitionCommandSpec command; private String label; // TransitionCommand parameters private String method; private int flags; // conditional link evaluation expression private Expression evaluation; private Map<String, String> uriParameters; private String linkId; // optional field which causes this transition private String sourceField; public String getLinkId() { return linkId; } public void setLinkId(String linkId) { this.linkId = linkId; } public ResourceState getSource() { return source; } public void setSource(ResourceState source) { this.source = source; } public ResourceState getTarget() { return target; } public void setTarget(ResourceState target) { this.target = target; } public TransitionCommandSpec getCommand() { return command; } public String getLabel() { return label; } /** * This method returns the field/property name which causes this transition * to come to exist, if applicable. * * @return the sourceField */ public String getSourceField() { return sourceField; } /** * @param sourceField the sourceField to set */ public void setSourceField(String sourceField) { this.sourceField = sourceField; } public String getId() { String labelText = ""; if (label != null && !label.equals((target != null ? target.getName() : ""))) { labelText = "(" + label + ")"; } if (source == null) { return target.getId() + ">" + command.getMethod() + labelText + ">" + target.getId(); //transition to itself } else { return source.getId() + ">" + command.getMethod() + labelText + ">" + (target != null ? target.getId() : ""); } } /** * Indicates whether this is a GET transition from a collection resource state * to an entity resource state within the same entity. * @return true/false */ public boolean isGetFromCollectionToEntityResource() { return source != null && command.getMethod() != null && command.getMethod().equals("GET") && source.getEntityName().equals(target.getEntityName()) && source instanceof CollectionResourceState && (target instanceof ResourceState && !(target instanceof CollectionResourceState)); } /** * @return the locator */ public ResourceLocator getLocator() { return locator; } /** * @param locator the locator to set */ public void setLocator(ResourceLocator locator) { this.locator = locator; } public boolean equals(Object other) { //check for self-comparison if (this == other) return true; if (!(other instanceof Transition)) return false; Transition otherTrans = (Transition) other; // Don't compare transitions to avoid recursion return isSameStateName(source, otherTrans.source) && isSameStateName(target, otherTrans.target) && StringUtils.equals(label, otherTrans.label) && ObjectUtils.equals(command, otherTrans.command) && StringUtils.equals(linkId, otherTrans.linkId) && StringUtils.equals(sourceField, otherTrans.sourceField); } private static boolean isSameStateName(ResourceState state1, ResourceState state2) { boolean same = false; if(state1 == null && state2 == null) { same = true; } else { if(state1 != null && state2 != null) { same = StringUtils.equals(state1.getName(), state2.getName()); } } return same; } public boolean isType(int type) { return (command.getFlags() & type) == type; } public boolean isAuto() { return command.isAutoTransition(); } public boolean isAnyOfTypes(int... types) { for(int type : types) { if (isType(type)) return true; } return false; } public int hashCode() { return (source != null ? source.getName().hashCode() : 0) + (target != null ? target.getName().hashCode() : 0) + (label != null ? label.hashCode() : 0) + (command != null ? command.hashCode() : 0) + (linkId != null ? linkId.hashCode() : 0); } public String toString() { return getId(); } /* * Builder pattern generated with fastcode eclipse plugin, you can just regenerate this part */ public static class Builder { private ResourceState source; private ResourceState target; private ResourceLocator locator; private String label; private String method; private int flags; private Expression evaluation; private Map<String, String> uriParameters; private String linkId; private String sourceField; public Builder source(ResourceState source) { this.source = source; return this; } public Builder target(ResourceState target) { this.target = target; return this; } public Builder locator(ResourceLocator locator) { this.locator = locator; return this; } public Builder label(String label) { this.label = label; return this; } public Builder method(String method) { this.method = method; return this; } public Builder flags(int flags) { this.flags = flags; return this; } public Builder evaluation(Expression evaluation) { this.evaluation = evaluation; return this; } public Builder uriParameters(Map<String, String> uriParameters) { this.uriParameters = uriParameters; return this; } public Builder linkId(String linkId) { this.linkId = linkId; return this; } public Builder sourceField(String sourceField) { this.sourceField = sourceField; return this; } public Transition build() { return new Transition(this); } } private Transition(Builder builder) { this.source = builder.source; this.target = builder.target; this.locator = builder.locator; this.label = builder.label; this.method = builder.method; this.flags = builder.flags; this.evaluation = builder.evaluation; this.uriParameters = builder.uriParameters; this.linkId = builder.linkId; this.sourceField = builder.sourceField; // this one's a bit special this.command = new TransitionCommandSpec(method, flags, evaluation, uriParameters, linkId); } }