/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.wkf.node;
import java.util.Vector;
import java.util.logging.Level;
import org.openflexo.foundation.Inspectors;
import org.openflexo.foundation.bindings.AbstractBinding;
import org.openflexo.foundation.bindings.BindingDefinition.BindingDefinitionType;
import org.openflexo.foundation.bindings.WKFBindingDefinition;
import org.openflexo.foundation.validation.ValidationIssue;
import org.openflexo.foundation.validation.ValidationRule;
import org.openflexo.foundation.validation.ValidationWarning;
import org.openflexo.foundation.wkf.FlexoProcess;
import org.openflexo.foundation.wkf.Status;
import org.openflexo.foundation.wkf.dm.PostInserted;
import org.openflexo.foundation.wkf.dm.PostRemoved;
import org.openflexo.foundation.wkf.dm.WKFAttributeDataModification;
import org.openflexo.foundation.wkf.edge.ContextualEdgeStarting;
import org.openflexo.foundation.wkf.edge.FlexoPostCondition;
import org.openflexo.foundation.xml.FlexoProcessBuilder;
import org.openflexo.localization.FlexoLocalization;
public class IFOperator extends OperatorNode implements ContextualEdgeStarting {
/**
* Stores the outgoing post conditions for Negative result, as a Vector of OperatorExit
*/
private Vector<FlexoPostCondition<AbstractNode, AbstractNode>> _positiveEvaluationOutgoingPostConditions;
/**
* Stores the outgoing post conditions for negative result, as a Vector of OperatorExit
*/
private Vector<FlexoPostCondition<AbstractNode, AbstractNode>> _negativeEvaluationOutgoingPostConditions;
public static final String CONDITION_PRIMITIVE = "conditionPrimitive";
private AbstractBinding _conditionPrimitive;
private Status newStatusForPositiveEvaluation;
private String newStatusForPositiveEvaluationAsString;
private Status newStatusForNegativeEvaluation;
private String newStatusForNegativeEvaluationAsString;
/**
* Constructor used during deserialization
*/
public IFOperator(FlexoProcessBuilder builder) {
this(builder.process);
initializeDeserialization(builder);
}
/**
* Default constructor
*/
public IFOperator(FlexoProcess process) {
super(process);
_positiveEvaluationOutgoingPostConditions = new Vector<FlexoPostCondition<AbstractNode, AbstractNode>>();
_negativeEvaluationOutgoingPostConditions = new Vector<FlexoPostCondition<AbstractNode, AbstractNode>>();
}
@Override
public String getInspectorName() {
return Inspectors.WKF.OPERATOR_IF_INSPECTOR;
}
/**
* Returns the outgoing post conditions for positive evaluation, as a Vector of OperatorExit
*/
public Vector<FlexoPostCondition<AbstractNode, AbstractNode>> getPositiveEvaluationPostConditions() {
return _positiveEvaluationOutgoingPostConditions;
}
public void setPositiveEvaluationPostConditions(Vector<FlexoPostCondition<AbstractNode, AbstractNode>> postConditions) {
_positiveEvaluationOutgoingPostConditions = postConditions;
}
public void removeFromPositiveEvaluationPostConditions(FlexoPostCondition post) {
if (_positiveEvaluationOutgoingPostConditions.contains(post)) {
_positiveEvaluationOutgoingPostConditions.remove(post);
post.setStartNode(null);
setChanged();
notifyObservers(new PostRemoved(post));
}
}
public void addToPositiveEvaluationPostConditions(FlexoPostCondition post) {
if (!_positiveEvaluationOutgoingPostConditions.contains(post) && post.getStartNodeClass().isAssignableFrom(getClass())) {
_positiveEvaluationOutgoingPostConditions.add(post);
post.setStartNode(this);
setChanged();
notifyObservers(new PostInserted(post));
notifyPostInsertedToProcess(post);
}
}
/**
* Returns the outgoing post conditions for Negative evaluation, as a Vector of OperatorExit
*/
public Vector<FlexoPostCondition<AbstractNode, AbstractNode>> getNegativeEvaluationPostConditions() {
return _negativeEvaluationOutgoingPostConditions;
}
public void setNegativeEvaluationPostConditions(Vector<FlexoPostCondition<AbstractNode, AbstractNode>> postConditions) {
_negativeEvaluationOutgoingPostConditions = postConditions;
}
public void removeFromNegativeEvaluationPostConditions(FlexoPostCondition post) {
if (_negativeEvaluationOutgoingPostConditions.contains(post)) {
_negativeEvaluationOutgoingPostConditions.remove(post);
post.setStartNode(null);
setChanged();
notifyObservers(new PostRemoved(post));
}
}
public void addToNegativeEvaluationPostConditions(FlexoPostCondition post) {
if (!_negativeEvaluationOutgoingPostConditions.contains(post) && post.getStartNodeClass().isAssignableFrom(getClass())) {
_negativeEvaluationOutgoingPostConditions.add(post);
post.setStartNode(this);
setChanged();
notifyObservers(new PostInserted(post));
notifyPostInsertedToProcess(post);
}
}
@Override
public Vector<FlexoPostCondition<AbstractNode, AbstractNode>> getOutgoingPostConditions() {
Vector<FlexoPostCondition<AbstractNode, AbstractNode>> returned = new Vector<FlexoPostCondition<AbstractNode, AbstractNode>>();
returned.addAll(_positiveEvaluationOutgoingPostConditions);
returned.addAll(_negativeEvaluationOutgoingPostConditions);
return returned;
}
@Override
public void setOutgoingPostConditions(Vector<FlexoPostCondition<AbstractNode, AbstractNode>> postConditions) {
// Not applicable
}
@Override
public void addToOutgoingPostConditions(FlexoPostCondition post) {
// Not applicable
/*logger.warning("addToOutgoingPostConditions() called in IFOperator with no context, use POSITIVE evaluation");
addToPositiveEvaluationPostConditions(post);*/
}
@Override
public void addToOutgoingPostConditions(FlexoPostCondition post, Object outputContext) {
logger.info("addToOutgoingPostConditions() called in IFOperator with context=" + outputContext);
if (outputContext.equals(Boolean.TRUE)) {
addToPositiveEvaluationPostConditions(post);
} else if (outputContext.equals(Boolean.FALSE)) {
addToNegativeEvaluationPostConditions(post);
} else {
logger.warning("INCONSISTENT DATA: addToOutgoingPostConditions() called in IFOperator with context=" + outputContext);
}
}
@Override
public void removeFromOutgoingPostConditions(FlexoPostCondition post) {
removeFromPositiveEvaluationPostConditions(post);
removeFromNegativeEvaluationPostConditions(post);
}
@Override
public String getDefaultName() {
return FlexoLocalization.localizedForKey("IF");
}
public WKFBindingDefinition getConditionPrimitiveBindingDefinition() {
if (getProject() != null) {
WKFBindingDefinition returned = WKFBindingDefinition.get(this, CONDITION_PRIMITIVE, Boolean.class, BindingDefinitionType.GET,
false);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Returned WKFBindingDefinition : " + returned);
}
return returned;
}
return null;
}
public AbstractBinding getConditionPrimitive() {
if (isBeingCloned()) {
return null;
}
return _conditionPrimitive;
}
public void setConditionPrimitive(AbstractBinding conditionPrimitive) {
AbstractBinding oldBindingValue = _conditionPrimitive;
_conditionPrimitive = conditionPrimitive;
if (_conditionPrimitive != null) {
_conditionPrimitive.setOwner(this);
_conditionPrimitive.setBindingDefinition(getConditionPrimitiveBindingDefinition());
}
setChanged();
notifyObservers(new WKFAttributeDataModification(CONDITION_PRIMITIVE, oldBindingValue, conditionPrimitive));
}
public boolean isPositiveEvaluationPostcondition(FlexoPostCondition post) {
return getPositiveEvaluationPostConditions().contains(post);
}
public boolean isNegativeEvaluationPostcondition(FlexoPostCondition post) {
return getNegativeEvaluationPostConditions().contains(post);
}
public Status getNewStatusForPositiveEvaluation() {
if (newStatusForPositiveEvaluation == null && newStatusForPositiveEvaluationAsString != null) {
if (getProject() != null) {
newStatusForPositiveEvaluation = getProject().getGlobalStatus().get(newStatusForPositiveEvaluationAsString);
if (newStatusForPositiveEvaluation == null && !isDeserializing()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Status with name " + newStatusForPositiveEvaluationAsString + " could not be found.");
}
newStatusForPositiveEvaluationAsString = null;
}
} else if (!isDeserializing()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("No project for Operation node " + getName());
}
}
}
return newStatusForPositiveEvaluation;
}
public void setNewStatusForPositiveEvaluation(Status newStatusForPositiveEvaluation) {
Status old = this.newStatusForPositiveEvaluation;
this.newStatusForPositiveEvaluation = newStatusForPositiveEvaluation;
notifyAttributeModification("newStatusForPositiveEvaluation", old, newStatusForPositiveEvaluation);
}
public String getNewStatusForPositiveEvaluationAsString() {
if (getNewStatusForPositiveEvaluation() != null) {
return getNewStatusForPositiveEvaluation().getFullyQualifiedName();
} else {
return null;
}
}
public void setNewStatusForPositiveEvaluationAsString(String newStatusForPositiveEvaluationAsString) {
this.newStatusForPositiveEvaluationAsString = newStatusForPositiveEvaluationAsString;
}
public Status getNewStatusForNegativeEvaluation() {
if (newStatusForNegativeEvaluation == null && newStatusForNegativeEvaluationAsString != null) {
if (getProject() != null) {
newStatusForNegativeEvaluation = getProject().getGlobalStatus().get(newStatusForNegativeEvaluationAsString);
if (newStatusForNegativeEvaluation == null && !isDeserializing()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Status with name " + newStatusForNegativeEvaluationAsString + " could not be found.");
}
newStatusForNegativeEvaluationAsString = null;
}
} else if (!isDeserializing()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("No project for Operation node " + getName());
}
}
}
return newStatusForNegativeEvaluation;
}
public void setNewStatusForNegativeEvaluation(Status newStatusForNegativeEvaluation) {
Status old = this.newStatusForNegativeEvaluation;
this.newStatusForNegativeEvaluation = newStatusForNegativeEvaluation;
notifyAttributeModification("newStatusForNegativeEvaluation", old, newStatusForNegativeEvaluation);
}
public String getNewStatusForNegativeEvaluationAsString() {
if (getNewStatusForNegativeEvaluation() != null) {
return getNewStatusForNegativeEvaluation().getFullyQualifiedName();
} else {
return null;
}
}
public void setNewStatusForNegativeEvaluationAsString(String newStatusForNegativeEvaluationAsString) {
this.newStatusForNegativeEvaluationAsString = newStatusForNegativeEvaluationAsString;
}
public static class CannotHaveMoreThanTwoOutgoingEdge extends ValidationRule<CannotHaveMoreThanTwoOutgoingEdge, IFOperator> {
public CannotHaveMoreThanTwoOutgoingEdge() {
super(IFOperator.class, "if_node_cannot_have_more_than_2_outgoing_flow");
}
@Override
public ValidationIssue<CannotHaveMoreThanTwoOutgoingEdge, IFOperator> applyValidation(IFOperator post) {
if (post.getOutgoingPostConditions().size() > 2) {
return new ValidationWarning<CannotHaveMoreThanTwoOutgoingEdge, IFOperator>(this, post,
"if_node_cannot_have_more_than_2_outgoing_flow");
}
if (post.getOutgoingPostConditions().size() < 2) {
return new ValidationWarning<CannotHaveMoreThanTwoOutgoingEdge, IFOperator>(this, post,
"if_node_cannot_have_less_than_2_outgoing_flow");
}
return null;
}
}
public static class MustHaveOnePositiveAndOneNegativeOutgoingFlow extends
ValidationRule<MustHaveOnePositiveAndOneNegativeOutgoingFlow, IFOperator> {
public MustHaveOnePositiveAndOneNegativeOutgoingFlow() {
super(IFOperator.class, "if_node_cannot_have_more_than_2_outgoing_flow");
}
@Override
public ValidationIssue<MustHaveOnePositiveAndOneNegativeOutgoingFlow, IFOperator> applyValidation(IFOperator post) {
if (post.getOutgoingPostConditions().size() == 2) {
FlexoPostCondition post1 = post.getOutgoingPostConditions().get(0);
FlexoPostCondition post2 = post.getOutgoingPostConditions().get(1);
if (post1.isPositiveEvaluation() != !post2.isPositiveEvaluation()) {
return new ValidationWarning<MustHaveOnePositiveAndOneNegativeOutgoingFlow, IFOperator>(this, post,
"if_node_must_have_exactly_one_positive_and_one_negative_outgoing_flow");
}
}
return null;
}
}
}