/* * (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.Hashtable; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.foundation.DataModification; import org.openflexo.foundation.FlexoObservable; import org.openflexo.foundation.FlexoObserver; import org.openflexo.foundation.bindings.Bindable; import org.openflexo.foundation.bindings.BindingModel; import org.openflexo.foundation.bindings.BindingVariable; import org.openflexo.foundation.ie.dm.BindingAdded; import org.openflexo.foundation.ie.dm.BindingRemoved; import org.openflexo.foundation.wkf.FlexoProcess; import org.openflexo.foundation.wkf.WKFObject; import org.openflexo.foundation.xml.FlexoProcessBuilder; import org.openflexo.toolbox.EmptyVector; /** * container for bindings in a ServiceOperation. a ServiceMessageBindings is roughly a Vector of ServiceMessageEntryBindings So containing * bindings related to 1 MessageDefinition, either an InputMessageDefinition, or an OutputMessageDefinition. * * the ServiceOperation has virtually 2 binding models: one for the inputMessage, one for the outputMessage Consequently, we define the * binding model in the ServiceOperation but this container is the Bindable object. * * * For an IN Operation, a binding defines for a variable 'a_pt' in the related Port's input message, the corresponding variable 'e_op' in * the Operation's input message: a_pt= f(e_op) * * For an OUT Operation, a binding defines for a variable 'd_op' in the operation's output message, the corresponding variable 'b_pt' in the * related Port's output message: d_op = f(a_pt) * * * * @author dvanvyve * */ public abstract class ServiceMessageBindings extends WKFObject implements Bindable, FlexoObserver { private static final Logger logger = Logger.getLogger(ServiceMessageBindings.class.getPackage().getName()); protected ServiceOperation _serviceOperation; protected AbstractMessageDefinition _messageDefinition; protected Vector<ServiceMessageEntryBinding> _bindings; /** * Constructor used during deserialization */ public ServiceMessageBindings(FlexoProcessBuilder builder) { this(builder.process); initializeDeserialization(builder); } /** * Default constructor */ public ServiceMessageBindings(FlexoProcess process) { super(process); _bindings = new Vector<ServiceMessageEntryBinding>(); } @Override public void initializeDeserialization(Object builder) { // setServiceOperation(((FlexoProcessBuilder)builder).serviceOperation); super.initializeDeserialization(builder); } @Override public abstract BindingModel getBindingModel(); @Override public Vector getAllEmbeddedWKFObjects() { // TODO Auto-generated method stub return null; } @Override public String getFullyQualifiedName() { // TODO Auto-generated method stub return null; } public String getInspectorName() { // Never inspected by its own return null; } public AbstractMessageDefinition getMessageDefinition() { return _messageDefinition; } 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() { if (logger.isLoggable(Level.FINE)) { logger.fine("lookup Binding " + getBindings().size() + " Entries of Message " + getMessageDefinition().getName()); } for (Enumeration<ServiceMessageEntryBinding> en = getBindings().elements(); en.hasMoreElements();) { ServiceMessageEntryBinding next = en.nextElement(); next.lookupBindingDefinition(); } } public ServiceOperation getServiceOperation() { return _serviceOperation; } public void setServiceOperation(ServiceOperation op) { _serviceOperation = op; // the owner of a BindingValue is this class and not the ServiceOperation /* * for (Enumeration en = getBindings().elements(); en.hasMoreElements();) { ServiceMessageEntryBinding next = * (ServiceMessageEntryBinding) en.nextElement(); if (next.getBindingValue() != null) { next.getBindingValue().setOwner(op); } } */ } public void addToBindings(ServiceMessageEntryBinding value) { value.setMessageBindings(this); _bindings.add(value); } public void removeFromBindings(ServiceMessageEntryBinding value) { if (logger.isLoggable(Level.FINE)) { logger.fine("Removing Binding in ServiceMessageBinding:" + value); } value.setMessageBindings(null); _bindings.remove(value); } public void setBindings(Vector<ServiceMessageEntryBinding> value) { _bindings = value; } public Vector<ServiceMessageEntryBinding> getBindings() { if (_bindings != null && getMessageDefinition() != null && _bindings.size() != getMessageDefinition().getEntries().size()) { updateBindings(); } return _bindings; } private boolean isRegistered(MessageEntry bd) { for (Enumeration<ServiceMessageEntryBinding> en = _bindings.elements(); en.hasMoreElements();) { ServiceMessageEntryBinding next = en.nextElement(); if (next.getBindingDefinition() == bd) { return true; } } return false; } public ServiceMessageEntryBinding getBinding(MessageEntry bd) { for (Enumeration<ServiceMessageEntryBinding> en = _bindings.elements(); en.hasMoreElements();) { ServiceMessageEntryBinding next = en.nextElement(); if (next.getBindingDefinition() == bd) { return next; } } return null; } private void updateBindings() { if (logger.isLoggable(Level.FINE)) { logger.fine("updateBindings() in ServiceMessageBindings"); } Vector toRemove = new Vector(); toRemove.addAll(_bindings); for (Enumeration en = getMessageDefinition().getEntries().elements(); en.hasMoreElements();) { MessageEntry next = (MessageEntry) en.nextElement(); if (!isRegistered(next)) { addToBindings(new ServiceMessageEntryBinding(this, next, null)); } else { toRemove.remove(getBinding(next)); } } for (Enumeration en = toRemove.elements(); en.hasMoreElements();) { ServiceMessageEntryBinding next = (ServiceMessageEntryBinding) en.nextElement(); removeFromBindings(next); } } @Override public void update(FlexoObservable o, DataModification dataModification) { if (logger.isLoggable(Level.FINE)) { logger.fine("received update in ServiceMessageBindings " + dataModification); } if (o == getMessageDefinition() && (dataModification instanceof BindingAdded || dataModification instanceof BindingRemoved)) { updateBindings(); } } @Override public void delete() { // getServiceOperation().setInputMessageBindings(null); // getServiceOperation().setOutputMessageBindings() Enumeration<ServiceMessageEntryBinding> en = new Vector<ServiceMessageEntryBinding>(_bindings).elements(); while (en.hasMoreElements()) { ServiceMessageEntryBinding binding = en.nextElement(); deleteBinding(binding); } _messageDefinition.delete(); _serviceOperation = null; _messageDefinition = null; _bindings.clear(); _bindings = null; super.delete(); setChanged(); // notifyObservers(new ServiceOperationRemoved(this)); deleteObservers(); } /** * 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 ServiceMessageEntryBinding 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; } } public void deleteBinding(ServiceMessageEntryBinding 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(ServiceMessageEntryBinding 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; } public abstract class DynamicBindingModel extends BindingModel { // Vector bindingVariables = vector of MessageEntries. of ServiceMessageDefinition !!! // constructed dynamically from MessageDefinition. @SuppressWarnings("hiding") private final Logger logger = Logger.getLogger(ServiceMessageBindings.DynamicBindingModel.class.getPackage().getName()); protected Hashtable variablesTable; public DynamicBindingModel() { super(); variablesTable = new Hashtable(); } protected abstract AbstractMessageDefinition getMessageDefinition(); @Override public int getBindingVariablesCount() { if (getMessageDefinition() != null && getMessageDefinition().getEntries() != null) { return getMessageDefinition().getEntries().size(); } return 0; } /** * the variablesTable contains only BindingVariables that have been requested by the 'getBidingVariableAt' method. * * @param entry * @return */ protected abstract BindingVariable addBindingVariableForEntry(MessageEntry entry); @Override public BindingVariable getBindingVariableAt(int index) { if (getMessageDefinition() != null && getMessageDefinition().getEntries() != null) { MessageEntry entry = getMessageDefinition().getEntries().elementAt(index); BindingVariable var = (BindingVariable) variablesTable.get(entry); // var=null;//to force recreating the var. if (var == null) { var = addBindingVariableForEntry(entry); } else { // apply changes if the entry have changed ! var.setVariableName(entry.getVariableName()); var.setType(entry.getType()); } if (logger.isLoggable(Level.FINE)) { logger.fine("Binding Model Variable:" + var.getVariableName() + " " + var); } return var; } return null; } @Override public BindingVariable bindingVariableNamed(String variableName) { for (int i = 0; i < getBindingVariablesCount(); i++) { BindingVariable next = getBindingVariableAt(i); if (next.getVariableName() != null && next.getVariableName().equals(variableName)) { return next; } } return null; } } // ========================================================================== // ============================== Validation // ================================ // ========================================================================== /* * public static class DefinedBindingsMustBeValid extends CheckAllBindingsRule { public DefinedBindingsMustBeValid() { * super("defined_bindings_must_be_valid"); } * * public ValidationIssue applyValidation(final Validable object) { CompoundIssue errors = null; final ServiceMessageBindings bindings = * (ServiceMessageBindings) object; Enumeration en = bindings.getBindings().elements(); while (en.hasMoreElements()) { * ServiceMessageEntryBinding binding = (ServiceMessageEntryBinding) en.nextElement(); BindingValue bv = binding.getBindingValue(); if * ((bv != null) && (!bv.isBindingValid())) { ValidationError error; error = new MissingRequiredBinding(bindings, binding) { 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"); } * * public ValidationIssue applyValidation(final Validable object) { CompoundIssue errors = null; final ServiceMessageBindings bindings = * (ServiceMessageBindings) object; Enumeration en = bindings.getBindings().elements(); while (en.hasMoreElements()) { * ServiceMessageEntryBinding binding = (ServiceMessageEntryBinding) en.nextElement(); if * (binding.getBindingDefinition().getIsMandatory()) { BindingValue bv = binding.getBindingValue(); if ((bv == null) || * (!bv.isBindingValid())) { ValidationError error; if (bv == null) { error = new MissingRequiredBinding(bindings, binding) { public * String getLocalizedMessage() { return getLocalizedErrorMessageForUndefinedAndRequiredValue(); } }; } else { // !bv.isBindingValid() * error = new MissingRequiredBinding(bindings, binding) { 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(ServiceMessageBindings.class, message); } * * public abstract ValidationIssue applyValidation(final Validable object); * * public class MissingRequiredBinding extends ValidationError { public ServiceMessageEntryBinding messageEntryBinding; * * public String bindingName; * * public String portName; * * public MissingRequiredBinding(ServiceMessageBindings message, ServiceMessageEntryBinding aMessageEntryBinding) { * super(CheckAllBindingsRule.this, message, null); messageEntryBinding = aMessageEntryBinding; bindingName = * messageEntryBinding.getBindingDefinitionName(); portName = message.getServiceOperation().getName(); 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); } * * public FlexoModelObject getSelectableObject() { return messageEntryBinding.getMessageBindings().getServiceOperation(); } } * * public class SetBinding extends FixProposal { private ServiceMessageEntryBinding componentInstanceBinding; * * public BindingValue bindingValue; * * public String bindingName; * * public SetBinding(ServiceMessageEntryBinding aMessageEntryBinding, BindingValue aBindingValue) { * super("set_binding_($bindingName)_to_($bindingValue.stringRepresentation)"); bindingValue = aBindingValue; bindingName = * aMessageEntryBinding.getBindingDefinitionName(); componentInstanceBinding = aMessageEntryBinding; } * * 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 "service_message_bindings"; } }