/*
* (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.ws;
import java.util.Enumeration;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.FlexoObserver;
import org.openflexo.foundation.Inspectors;
import org.openflexo.foundation.bindings.AbstractBinding;
import org.openflexo.foundation.bindings.Bindable;
import org.openflexo.foundation.bindings.BindingDefinition;
import org.openflexo.foundation.bindings.BindingModel;
import org.openflexo.foundation.bindings.BindingValue;
import org.openflexo.foundation.ie.dm.BindingAdded;
import org.openflexo.foundation.ie.dm.BindingRemoved;
import org.openflexo.foundation.validation.CompoundIssue;
import org.openflexo.foundation.validation.FixProposal;
import org.openflexo.foundation.validation.Validable;
import org.openflexo.foundation.validation.ValidationError;
import org.openflexo.foundation.validation.ValidationIssue;
import org.openflexo.foundation.validation.ValidationRule;
import org.openflexo.foundation.wkf.FlexoLevel;
import org.openflexo.foundation.wkf.FlexoProcess;
import org.openflexo.foundation.wkf.LevelledObject;
import org.openflexo.foundation.wkf.WKFObject;
import org.openflexo.foundation.wkf.edge.MessageEdge;
import org.openflexo.foundation.xml.FlexoProcessBuilder;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.EmptyVector;
public class MessageBindings extends WKFObject implements InspectableObject, Bindable, LevelledObject, FlexoObserver {
private static final Logger logger = Logger.getLogger(MessageBindings.class.getPackage().getName());
private MessageEdge _messageEdge;
private AbstractMessageDefinition _messageDefinition;
private Vector<MessageEntryBinding> _bindings;
/**
* Constructor used during deserialization
*/
public MessageBindings(FlexoProcessBuilder builder) {
this(builder.process);
initializeDeserialization(builder);
}
/**
* Default constructor
*/
public MessageBindings(FlexoProcess process) {
super(process);
_bindings = new Vector<MessageEntryBinding>();
}
/**
* Dynamic constructor
*/
public MessageBindings(MessageEdge messageEdge, AbstractMessageDefinition messageDefinition) {
this(messageEdge.getProcess());
setMessageEdge(messageEdge);
setMessageDefinition(messageDefinition);
}
@Override
public Vector getAllEmbeddedWKFObjects() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getFullyQualifiedName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getInspectorName() {
return Inspectors.WKF.MESSAGE_INSPECTOR;
}
public AbstractMessageDefinition getMessageDefinition() {
return _messageDefinition;
}
@Override
public String getName() {
if (getMessageDefinition() != null) {
return getMessageDefinition().getName();
}
return FlexoLocalization.localizedForKey("unbound");
}
@Override
public void setName(String aName) {
if (getMessageDefinition() != null) {
getMessageDefinition().setName(aName);
}
}
public void setMessageDefinition(AbstractMessageDefinition messageDefinition) {
if (messageDefinition != _messageDefinition) {
if (_messageDefinition != null) {
_messageDefinition.deleteObserver(this);
}
_messageDefinition = messageDefinition;
if (_messageDefinition != null) {
_messageDefinition.addObserver(this);
}
lookupBindingEntries();
}
}
private void lookupBindingEntries() {
for (Enumeration en = getBindings().elements(); en.hasMoreElements();) {
MessageEntryBinding next = (MessageEntryBinding) en.nextElement();
next.lookupBindingDefinition();
}
}
public MessageEdge getMessageEdge() {
return _messageEdge;
}
public void setMessageEdge(MessageEdge messageEdge) {
_messageEdge = messageEdge;
for (MessageEntryBinding b : getBindings()) {
if (b.getBindingValue() != null) {
b.getBindingValue().setOwner(messageEdge);
}
}
}
@Override
public BindingModel getBindingModel() {
if (getProcess() != null) {
return getProcess().getBindingModel();
} else {
return null;
}
}
public void addToBindings(MessageEntryBinding value) {
value.setMessageBindings(this);
_bindings.add(value);
}
public void removeFromBindings(MessageEntryBinding value) {
value.setMessageBindings(null);
_bindings.remove(value);
}
public void setBindings(Vector<MessageEntryBinding> value) {
_bindings = value;
}
public Vector<MessageEntryBinding> getBindings() {
if (_bindings != null && getMessageDefinition() != null && _bindings.size() != getMessageDefinition().getEntries().size()) {
updateBindings();
}
return _bindings;
}
private boolean isRegistered(MessageEntry bd) {
for (Enumeration en = _bindings.elements(); en.hasMoreElements();) {
MessageEntryBinding next = (MessageEntryBinding) en.nextElement();
if (next.getBindingDefinition() == bd) {
return true;
}
}
return false;
}
private MessageEntryBinding getBinding(MessageEntry bd) {
for (Enumeration en = _bindings.elements(); en.hasMoreElements();) {
MessageEntryBinding next = (MessageEntryBinding) en.nextElement();
if (next.getBindingDefinition() == bd) {
return next;
}
}
return null;
}
private void updateBindings() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("updateBindings() in MessageBindings");
}
Vector<MessageEntryBinding> toRemove = new Vector<MessageEntryBinding>();
toRemove.addAll(_bindings);
for (Enumeration en = getMessageDefinition().getEntries().elements(); en.hasMoreElements();) {
MessageEntry next = (MessageEntry) en.nextElement();
if (!isRegistered(next)) {
addToBindings(new MessageEntryBinding(this, next, null));
} else {
toRemove.remove(getBinding(next));
}
}
for (Enumeration en = toRemove.elements(); en.hasMoreElements();) {
MessageEntryBinding next = (MessageEntryBinding) en.nextElement();
// removeFromBindings(next);
}
}
@Override
public void update(FlexoObservable o, DataModification dataModification) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("received update in MessageBindings " + dataModification);
}
if (o == getMessageDefinition() && (dataModification instanceof BindingAdded || dataModification instanceof BindingRemoved)) {
updateBindings();
setChanged();
notifyObservers(dataModification);
}
}
/**
* Return a Vector of embedded IEObjects at this level. NOTE1: that this is NOT a recursive method NOTE2: return null, since there is no
* embedded IEObject
*
* @return null
*/
public Vector getEmbeddedIEObjects() {
return new Vector();
}
public MessageEntryBinding createNewBinding() {
if (getMessageDefinition() != null) {
MessageEntry newBD = getMessageDefinition().createNewMessageEntry();
return getBinding(newBD);
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not create binding: cannot access MessageDefinition !");
}
return null;
}
}
/**
*
*/
@Override
// final is for deleteObservers()
public final void delete() {
super.delete();
deleteObservers();
}
public void deleteBinding(MessageEntryBinding meb) {
if (getMessageDefinition() != null) {
getMessageDefinition().deleteMessageEntry(meb.getBindingDefinition());
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not delete binding: cannot access MessageDefinition !");
}
}
}
public boolean isBindingDeletable(MessageEntryBinding meb) {
if (getMessageDefinition() != null) {
return getMessageDefinition().isMessageEntryDeletable(meb.getBindingDefinition());
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not access binding: cannot access ComponentDefinition !");
}
}
return false;
}
// ==========================================================================
// ============================== Validation
// ================================
// ==========================================================================
public static class DefinedBindingsMustBeValid extends CheckAllBindingsRule {
public DefinedBindingsMustBeValid() {
super("defined_bindings_must_be_valid");
}
@Override
public ValidationIssue applyValidation(final Validable object) {
CompoundIssue errors = null;
final MessageBindings bindings = (MessageBindings) object;
Enumeration en = bindings.getBindings().elements();
while (en.hasMoreElements()) {
MessageEntryBinding binding = (MessageEntryBinding) en.nextElement();
AbstractBinding bv = binding.getBindingValue();
if (bv != null && !bv.isBindingValid()) {
ValidationError error;
error = new MissingRequiredBinding(bindings, binding) {
@Override
public String getLocalizedMessage() {
return getLocalizedErrorMessageForInvalidValue();
}
};
if (errors == null) {
errors = new CompoundIssue(object);
}
errors.addToContainedIssues(error);
}
}
return errors;
}
}
public static class MandatoryBindingsMustHaveAValue extends CheckAllBindingsRule {
public MandatoryBindingsMustHaveAValue() {
super("mandatory_bindings_must_have_a_value");
}
@Override
public ValidationIssue applyValidation(final Validable object) {
CompoundIssue errors = null;
final MessageBindings bindings = (MessageBindings) object;
Enumeration en = bindings.getBindings().elements();
while (en.hasMoreElements()) {
MessageEntryBinding binding = (MessageEntryBinding) en.nextElement();
if (binding.getBindingDefinition().getIsMandatory()) {
AbstractBinding bv = binding.getBindingValue();
if (bv == null || !bv.isBindingValid()) {
ValidationError error;
if (bv == null) {
error = new MissingRequiredBinding(bindings, binding) {
@Override
public String getLocalizedMessage() {
return getLocalizedErrorMessageForUndefinedAndRequiredValue();
}
};
} else { // !bv.isBindingValid()
error = new MissingRequiredBinding(bindings, binding) {
@Override
public String getLocalizedMessage() {
return getLocalizedErrorMessageForInvalidAndRequiredValue();
}
};
}
if (errors == null) {
errors = new CompoundIssue(object);
}
errors.addToContainedIssues(error);
}
}
}
return errors;
}
}
public abstract static class CheckAllBindingsRule extends ValidationRule {
public CheckAllBindingsRule(String message) {
super(MessageBindings.class, message);
}
@Override
public abstract ValidationIssue applyValidation(final Validable object);
public class MissingRequiredBinding extends ValidationError {
public MessageEntryBinding messageEntryBinding;
public String bindingName;
public String portName;
public MissingRequiredBinding(MessageBindings message, MessageEntryBinding aMessageEntryBinding) {
super(CheckAllBindingsRule.this, message, null);
messageEntryBinding = aMessageEntryBinding;
bindingName = messageEntryBinding.getBindingDefinitionName();
if (message.getMessageEdge().getFlexoPort() != null) {
portName = message.getMessageEdge().getFlexoPort().getName();
} else {
portName = "null";
}
BindingDefinition bd = aMessageEntryBinding.getBindingDefinition();
if (bd != null) {
Vector allAvailableBV = bd.searchMatchingBindingValue(message, 2);
for (int i = 0; i < allAvailableBV.size(); i++) {
BindingValue proposal = (BindingValue) allAvailableBV.elementAt(i);
addToFixProposals(new SetBinding(aMessageEntryBinding, proposal));
}
}
}
public String getLocalizedErrorMessageForUndefinedAndRequiredValue() {
return FlexoLocalization.localizedForKeyWithParams(
"binding_named_($bindingName)_required_by_port_($portName)_is_not_defined", this);
}
public String getLocalizedErrorMessageForInvalidAndRequiredValue() {
return FlexoLocalization.localizedForKeyWithParams(
"binding_named_($bindingName)_required_by_port_($portName)_has_invalid_value", this);
}
public String getLocalizedErrorMessageForInvalidValue() {
return FlexoLocalization.localizedForKeyWithParams("binding_named_($bindingName)_has_invalid_value", this);
}
@Override
public FlexoModelObject getSelectableObject() {
return messageEntryBinding.getMessageBindings().getMessageEdge();
}
}
public class SetBinding extends FixProposal {
private MessageEntryBinding componentInstanceBinding;
public BindingValue bindingValue;
public String bindingName;
public SetBinding(MessageEntryBinding aMessageEntryBinding, BindingValue aBindingValue) {
super("set_binding_($bindingName)_to_($bindingValue.stringRepresentation)");
bindingValue = aBindingValue;
bindingName = aMessageEntryBinding.getBindingDefinitionName();
componentInstanceBinding = aMessageEntryBinding;
}
@Override
protected void fixAction() {
componentInstanceBinding.setBindingValue(bindingValue);
}
public String getBindingName() {
return bindingName;
}
public void setBindingName() {
}
}
}
/**
* Overrides getAllEmbeddedDeleted
*
* @see org.openflexo.foundation.wkf.WKFObject#getAllEmbeddedDeleted()
*/
@Override
public Vector<WKFObject> getAllEmbeddedDeleted() {
return EmptyVector.EMPTY_VECTOR(WKFObject.class);
}
/**
* Overrides getClassNameKey
*
* @see org.openflexo.foundation.FlexoModelObject#getClassNameKey()
*/
@Override
public String getClassNameKey() {
return "message_bindings";
}
@Override
public FlexoLevel getLevel() {
if (_messageEdge != null) {
return _messageEdge.getLevel();
}
return FlexoLevel.ACTIVITY;
}
/*
* @Override public void setLocation(Point newLocation) { logger.info("setLocation() from "+getLocation()+" to "+newLocation);
* super.setLocation(newLocation);
*
* }
*/
}