diff --git a/api/src/main/java/org/switchyard/Context.java b/api/src/main/java/org/switchyard/Context.java index 6ab89a6f8..a70310659 100644 --- a/api/src/main/java/org/switchyard/Context.java +++ b/api/src/main/java/org/switchyard/Context.java @@ -26,6 +26,13 @@ * service consumer and provider. */ public interface Context { + + /** + * Creates a shallow copy of the existing Context including all properties in all scopes. + * Properties with a label of Labels.TRANSIENT are not included in the copy. + * @return a copy of this context + */ + Context copy(); /** * Retrieves the named property within this context, regardless @@ -74,6 +81,13 @@ public interface Context { * scope. If there are no properties in the scope, an empty set is returned. */ Set getProperties(Scope scope); + + /** + * Get all properties with a given label. + * @param label the label each property must have + * @return set of properties with the specified label + */ + Set getProperties(String label); /** * Removes the named property from this context. @@ -92,6 +106,12 @@ public interface Context { * @param scope scope of the properties to remove */ void removeProperties(Scope scope); + + /** + * Remove all properties with a given label. + * @param label the label each property must have + */ + void removeProperties(String label); /** * Sets the named context property with the specified value. If the context diff --git a/api/src/main/java/org/switchyard/Labels.java b/api/src/main/java/org/switchyard/Labels.java new file mode 100644 index 000000000..3d7613de6 --- /dev/null +++ b/api/src/main/java/org/switchyard/Labels.java @@ -0,0 +1,38 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.switchyard; + +/** + * This class contains constant declarations for well-known context property labels. + */ +public final class Labels { + + /** + * Properties labeled as transient are not serialized and are not preserved in + * a copy of the exchange via Context.copy(). + */ + public static final String TRANSIENT = "org.switchyard.labels.transient"; + + /** + * Prevent instantiation of this class + */ + private Labels() { + + } +} diff --git a/api/src/main/java/org/switchyard/Property.java b/api/src/main/java/org/switchyard/Property.java index d25b6bb92..9be896c0d 100644 --- a/api/src/main/java/org/switchyard/Property.java +++ b/api/src/main/java/org/switchyard/Property.java @@ -1,6 +1,3 @@ -package org.switchyard; - -import java.util.Set; /* * JBoss, Home of Professional Open Source * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors @@ -20,11 +17,15 @@ * MA 02110-1301, USA. */ +package org.switchyard; + +import java.util.Set; + /** * Represents a context property consisting of a name, scope, and value. */ public interface Property { - + /** * The scope of the property. * @return property scope diff --git a/api/src/main/java/org/switchyard/policy/PolicyUtil.java b/api/src/main/java/org/switchyard/policy/PolicyUtil.java index 37e7df239..ea8bb23ea 100644 --- a/api/src/main/java/org/switchyard/policy/PolicyUtil.java +++ b/api/src/main/java/org/switchyard/policy/PolicyUtil.java @@ -23,6 +23,7 @@ import java.util.Set; import org.switchyard.Exchange; +import org.switchyard.Labels; import org.switchyard.Property; /** @@ -48,7 +49,7 @@ private PolicyUtil() { public static void provide(Exchange exchange, Policy policy) { Set provided = getPolicies(exchange, PROVIDED_PROPERTY); provided.add(policy); - exchange.getContext().setProperty(PROVIDED_PROPERTY, provided); + exchange.getContext().setProperty(PROVIDED_PROPERTY, provided).addLabels(Labels.TRANSIENT); } /** @@ -78,7 +79,7 @@ public static boolean isProvided(Exchange exchange, Policy policy) { public static void require(Exchange exchange, Policy policy) { Set required = getPolicies(exchange, REQUIRED_PROPERTY); required.add(policy); - exchange.getContext().setProperty(REQUIRED_PROPERTY, required); + exchange.getContext().setProperty(REQUIRED_PROPERTY, required).addLabels(Labels.TRANSIENT); } /** diff --git a/api/src/main/java/org/switchyard/transform/TransformSequence.java b/api/src/main/java/org/switchyard/transform/TransformSequence.java index af9f3bcd3..122e187e5 100644 --- a/api/src/main/java/org/switchyard/transform/TransformSequence.java +++ b/api/src/main/java/org/switchyard/transform/TransformSequence.java @@ -27,6 +27,7 @@ import org.apache.log4j.Logger; import org.switchyard.Exchange; +import org.switchyard.Labels; import org.switchyard.Message; import org.switchyard.Property; import org.switchyard.Scope; @@ -71,7 +72,7 @@ private TransformSequence() { */ public void associateWith(Exchange exchange, Scope scope) { exchange.getContext().setProperty( - TransformSequence.class.getName(), this, scope); + TransformSequence.class.getName(), this, scope).addLabels(Labels.TRANSIENT); } /** diff --git a/api/src/test/java/org/switchyard/MockContext.java b/api/src/test/java/org/switchyard/MockContext.java index 41b8f421f..56d78c602 100644 --- a/api/src/test/java/org/switchyard/MockContext.java +++ b/api/src/test/java/org/switchyard/MockContext.java @@ -36,6 +36,14 @@ public class MockContext implements Context { private final Map _outProperties = Collections.synchronizedMap(new HashMap()); public MockContext() {} + + private MockContext(Map exchangeProps, + Map inProps, + Map outProps) { + _exchangeProperties.putAll(exchangeProps); + _inProperties.putAll(inProps); + _outProperties.putAll(outProps); + } private Map getPropertiesMap(Scope scope) { switch (scope) { @@ -153,4 +161,31 @@ public Context setProperties(Set properties) { return this; } + @Override + public Context copy() { + MockContext ctx = new MockContext(_exchangeProperties, _inProperties, _outProperties); + ctx.removeProperties(Labels.TRANSIENT); + return ctx; + } + + @Override + public Set getProperties(String label) { + Set props = new HashSet(); + for (Property p : getProperties()) { + if (p.hasLabel(label)) { + props.add(p); + } + } + return props; + } + + @Override + public void removeProperties(String label) { + for (Property p : getProperties()) { + if (p.hasLabel(label)) { + removeProperty(p); + } + } + } + } diff --git a/config/src/main/java/org/switchyard/config/model/composite/SCABindingModel.java b/config/src/main/java/org/switchyard/config/model/composite/SCABindingModel.java new file mode 100644 index 000000000..eb06e898d --- /dev/null +++ b/config/src/main/java/org/switchyard/config/model/composite/SCABindingModel.java @@ -0,0 +1,123 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.switchyard.config.model.composite; + +import javax.xml.namespace.QName; + +import org.switchyard.config.model.switchyard.SwitchYardModel; + +/** + * SCABindingModel represents the standard binding.sca binding in SCA. SwitchYard supports a + * set of extensions which are represented as attributes on the binding.sca element which are exposed + * via this config model. + */ +public interface SCABindingModel extends BindingModel { + + /** The "sca" name. */ + public static final String SCA = "sca"; + + /** The "target" name. */ + public static final QName TARGET = new QName(SwitchYardModel.DEFAULT_NAMESPACE, "target"); + + /** The "target" name. */ + public static final QName TARGET_NAMESPACE = new QName(SwitchYardModel.DEFAULT_NAMESPACE, "targetNamespace"); + + /** The "loadBalance" name. */ + public static final QName LOAD_BALANCE = new QName(SwitchYardModel.DEFAULT_NAMESPACE, "loadBalance"); + + /** The "clustered" name. */ + public static final QName CLUSTERED = new QName(SwitchYardModel.DEFAULT_NAMESPACE, "clustered"); + + /** + * Indicates whether clustering is enabled. + * @return true if clustering is enabled, false otherwise + */ + boolean isClustered(); + + /** + * Specifies whether clustering is enabled for the service binding. Valid for service and + * reference bindings. + * @param clustered true for enabled, false for disabled + * @return this config model instance + */ + SCABindingModel setClustered(boolean clustered); + + /** + * Indicates whether load balancing is enabled. + * @return true if load balancing is enabled, false otherwise + */ + boolean isLoadBalanced(); + + /** + * Returns the load balance strategy used by the binding. + * @return the load balance strategy in use + */ + String getLoadBalance(); + + /** + * Specifies the strategy used for load balancing. This attribute is only valid for reference + * bindings. + * @param loadBalance the load balance strategy used + * @return this config model instance + */ + SCABindingModel setLoadBalance(String loadBalance); + + /** + * Indicates whether a target service has been specified for the binding. + * @return true if a target service is specified, false otherwise + */ + boolean hasTarget(); + + /** + * Returns the target service name used for the binding. + * @return target service name + */ + String getTarget(); + + /** + * Specifies the target service name used for this binding. This is valid for reference + * bindings only and allows the service name to be overloaded in case the provider service + * has a different name. + * @param target target service name + * @return this config model instance + */ + SCABindingModel setTarget(String target); + + /** + * Indicates whether a target namespace has been specified for the binding. + * @return true if a target namespace is specified, false otherwise + */ + boolean hasTargetNamespace(); + + /** + * Returns the target namespace used for the binding. + * @return target namespace + */ + String getTargetNamespace(); + + /** + * Specifies the target namespace used for this binding. This is valid for reference + * bindings only and allows the service namespace to be overloaded in case the provider service + * has a different namespace. + * @param namespace target service namespace + * @return this config model instance + */ + SCABindingModel setTargetNamespace(String namespace); +} diff --git a/config/src/main/java/org/switchyard/config/model/composite/v1/V1CompositeMarshaller.java b/config/src/main/java/org/switchyard/config/model/composite/v1/V1CompositeMarshaller.java index c410ce6c8..3e9f2da75 100644 --- a/config/src/main/java/org/switchyard/config/model/composite/v1/V1CompositeMarshaller.java +++ b/config/src/main/java/org/switchyard/config/model/composite/v1/V1CompositeMarshaller.java @@ -30,6 +30,7 @@ import org.switchyard.config.model.composite.CompositeModel; import org.switchyard.config.model.composite.CompositeServiceModel; import org.switchyard.config.model.composite.InterfaceModel; +import org.switchyard.config.model.composite.SCABindingModel; import org.switchyard.config.model.property.PropertyModel; import org.switchyard.config.model.property.v1.V1PropertyModel; @@ -67,7 +68,11 @@ public Model read(Configuration config) { } } } else if (name.startsWith(BindingModel.BINDING)) { - return new V1BindingModel(config, desc); + if (name.endsWith("." + SCABindingModel.SCA)) { + return new V1SCABindingModel(config, desc); + } else { + return new V1BindingModel(config, desc); + } } else if (name.equals(ComponentModel.COMPONENT)) { return new V1ComponentModel(config, desc); } else if (name.startsWith(ComponentImplementationModel.IMPLEMENTATION)) { @@ -92,6 +97,7 @@ public Model read(Configuration config) { } else if (name.equals(PropertyModel.PROPERTY)) { return new V1PropertyModel(config,desc); } + return null; } diff --git a/config/src/main/java/org/switchyard/config/model/composite/v1/V1SCABindingModel.java b/config/src/main/java/org/switchyard/config/model/composite/v1/V1SCABindingModel.java new file mode 100644 index 000000000..0bc416b89 --- /dev/null +++ b/config/src/main/java/org/switchyard/config/model/composite/v1/V1SCABindingModel.java @@ -0,0 +1,107 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.switchyard.config.model.composite.v1; + +import org.switchyard.config.Configuration; +import org.switchyard.config.model.Descriptor; +import org.switchyard.config.model.composite.CompositeModel; +import org.switchyard.config.model.composite.SCABindingModel; + +/** + * V1 implementation in SCABindingModel. + */ +public class V1SCABindingModel extends V1BindingModel implements SCABindingModel { + + /** + * Create a new V1SCABindingModel. + */ + public V1SCABindingModel() { + super(SCABindingModel.SCA, CompositeModel.DEFAULT_NAMESPACE); + } + + /** + * Create a new V1SCABindingModel. + * @param config raw config model + * @param desc descriptor + */ + public V1SCABindingModel(Configuration config, Descriptor desc) { + super(config, desc); + } + + @Override + public boolean isClustered() { + return Boolean.valueOf(getModelAttribute(CLUSTERED)); + } + + @Override + public SCABindingModel setClustered(boolean clustered) { + setModelAttribute(CLUSTERED, String.valueOf(clustered)); + return this; + } + + @Override + public boolean isLoadBalanced() { + return getLoadBalance() != null; + } + + @Override + public String getLoadBalance() { + return getModelAttribute(LOAD_BALANCE); + } + + @Override + public SCABindingModel setLoadBalance(String loadBalance) { + setModelAttribute(LOAD_BALANCE, loadBalance); + return this; + } + + @Override + public boolean hasTarget() { + return getTarget() != null; + } + + @Override + public String getTarget() { + return getModelAttribute(TARGET); + } + + @Override + public SCABindingModel setTarget(String target) { + setModelAttribute(TARGET, target); + return this; + } + + @Override + public boolean hasTargetNamespace() { + return getTargetNamespace() != null; + } + + @Override + public String getTargetNamespace() { + return getModelAttribute(TARGET_NAMESPACE); + } + + @Override + public SCABindingModel setTargetNamespace(String namespace) { + setModelAttribute(TARGET_NAMESPACE, namespace); + return this; + } + +} diff --git a/config/src/main/resources/org/switchyard/config/model/switchyard/v1/switchyard-v1.xsd b/config/src/main/resources/org/switchyard/config/model/switchyard/v1/switchyard-v1.xsd index 51af04820..5ff021d9e 100644 --- a/config/src/main/resources/org/switchyard/config/model/switchyard/v1/switchyard-v1.xsd +++ b/config/src/main/resources/org/switchyard/config/model/switchyard/v1/switchyard-v1.xsd @@ -247,5 +247,11 @@ MA 02110-1301, USA. - + + + + + + + diff --git a/config/src/test/java/org/switchyard/config/model/composite/CompositeModelTests.java b/config/src/test/java/org/switchyard/config/model/composite/CompositeModelTests.java index 32b672ccd..1047a131b 100644 --- a/config/src/test/java/org/switchyard/config/model/composite/CompositeModelTests.java +++ b/config/src/test/java/org/switchyard/config/model/composite/CompositeModelTests.java @@ -59,6 +59,7 @@ public class CompositeModelTests { private static final String COMPLETE_XML = "/org/switchyard/config/model/composite/CompositeModelTests-Complete.xml"; private static final String EXTENDED_XML = "/org/switchyard/config/model/composite/CompositeModelTests-Extended.xml"; private static final String EXTENSION_XML = "/org/switchyard/config/model/composite/CompositeModelTests-Extension.xml"; + private static final String SCA_BINDING_XML = "/org/switchyard/config/model/composite/CompositeModelTests-SCABinding.xml"; private static ModelPuller _puller; @@ -262,6 +263,21 @@ public void testReadExtensionRefferingNoNamespacedSchema() throws Exception { assertEquals("Bar", extension.getGroup()); assertEquals("Foo", extension.getName()); } + + @Test + public void testSCABinding() throws Exception { + CompositeModel composite = _puller.pull(SCA_BINDING_XML, getClass()); + + // test binding.sca on composite service + CompositeServiceModel compositeService = composite.getServices().get(0); + BindingModel sb = compositeService.getBindings().get(0); + assertTrue(sb instanceof SCABindingModel); + + // test binding.sca on composite reference + CompositeReferenceModel compositeReference = composite.getReferences().get(0); + BindingModel rb = compositeReference.getBindings().get(0); + assertTrue(sb instanceof SCABindingModel); + } @Test public void testValidationOfExtensionRefferingNoNamespacedSchema() throws Exception { diff --git a/config/src/test/java/org/switchyard/config/model/switchyard/SCABindingExtensionTests.java b/config/src/test/java/org/switchyard/config/model/switchyard/SCABindingExtensionTests.java new file mode 100644 index 000000000..da0223d4b --- /dev/null +++ b/config/src/test/java/org/switchyard/config/model/switchyard/SCABindingExtensionTests.java @@ -0,0 +1,88 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.switchyard.config.model.switchyard; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.switchyard.config.model.ModelPuller; +import org.switchyard.config.model.composite.SCABindingModel; +import org.switchyard.config.model.composite.v1.V1SCABindingModel; + +/** + * SCABindingExtensionTests. + */ +public class SCABindingExtensionTests { + + private static final String SCA_BINDING_XML = "/org/switchyard/config/model/switchyard/SCABindingTests.xml"; + + private ModelPuller _puller; + + @Before + public void before() throws Exception { + _puller = new ModelPuller(); + } + + @Test + public void testCreate() throws Exception { + final String TARGET = "foo"; + final String TARGET_NS = "urn:bar"; + final String STRATEGY = "RoundRobin"; + + SCABindingModel scab = new V1SCABindingModel(); + scab.setClustered(true) + .setLoadBalance(STRATEGY) + .setTarget(TARGET) + .setTargetNamespace(TARGET_NS); + + Assert.assertEquals(STRATEGY, scab.getLoadBalance()); + Assert.assertEquals(TARGET, scab.getTarget()); + Assert.assertEquals(TARGET_NS, scab.getTargetNamespace()); + + Assert.assertTrue(scab.isClustered()); + Assert.assertTrue(scab.hasTarget()); + Assert.assertTrue(scab.hasTargetNamespace()); + Assert.assertTrue(scab.isLoadBalanced()); + } + + @Test + public void testRead() throws Exception { + SwitchYardModel switchyard = _puller.pull(SCA_BINDING_XML, getClass()); + SCABindingModel sb = (SCABindingModel)switchyard.getComposite().getServices().get(0).getBindings().get(0); + SCABindingModel rb = (SCABindingModel)switchyard.getComposite().getReferences().get(0).getBindings().get(0); + + Assert.assertTrue(sb.isClustered()); + Assert.assertFalse(sb.isLoadBalanced()); + Assert.assertFalse(sb.hasTarget()); + Assert.assertFalse(sb.hasTargetNamespace()); + + Assert.assertTrue(rb.isClustered()); + Assert.assertEquals("RoundRobin", rb.getLoadBalance()); + Assert.assertEquals("somethingElse", rb.getTarget()); + Assert.assertEquals("urn:another:uri", rb.getTargetNamespace()); + } + + @Test + public void testValidation() throws Exception { + SwitchYardModel switchyard = _puller.pull(SCA_BINDING_XML, getClass()); + switchyard.assertModelValid(); + } + +} diff --git a/config/src/test/resources/org/switchyard/config/model/composite/CompositeModelTests-SCABinding.xml b/config/src/test/resources/org/switchyard/config/model/composite/CompositeModelTests-SCABinding.xml new file mode 100644 index 000000000..5f45f1c3c --- /dev/null +++ b/config/src/test/resources/org/switchyard/config/model/composite/CompositeModelTests-SCABinding.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/switchyard/config/model/switchyard/SCABindingTests.xml b/config/src/test/resources/org/switchyard/config/model/switchyard/SCABindingTests.xml new file mode 100644 index 000000000..8b024ac63 --- /dev/null +++ b/config/src/test/resources/org/switchyard/config/model/switchyard/SCABindingTests.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/remote/src/main/java/org/switchyard/remote/cluster/BaseStrategy.java b/remote/src/main/java/org/switchyard/remote/cluster/BaseStrategy.java index c9302e83c..cf447ec3a 100644 --- a/remote/src/main/java/org/switchyard/remote/cluster/BaseStrategy.java +++ b/remote/src/main/java/org/switchyard/remote/cluster/BaseStrategy.java @@ -27,13 +27,13 @@ public abstract class BaseStrategy implements LoadBalanceStrategy { private RemoteRegistry _registry; - protected BaseStrategy(RemoteRegistry registry) { - _registry = registry; - } - @Override public RemoteRegistry getRegistry() { return _registry; } + @Override + public void setRegistry(RemoteRegistry registry) { + _registry = registry; + } } diff --git a/remote/src/main/java/org/switchyard/remote/cluster/ClusteredInvoker.java b/remote/src/main/java/org/switchyard/remote/cluster/ClusteredInvoker.java index b11833df3..951d00899 100644 --- a/remote/src/main/java/org/switchyard/remote/cluster/ClusteredInvoker.java +++ b/remote/src/main/java/org/switchyard/remote/cluster/ClusteredInvoker.java @@ -41,17 +41,19 @@ public class ClusteredInvoker implements RemoteInvoker { * @param registry remote registry */ public ClusteredInvoker(RemoteRegistry registry) { - this(new RoundRobinStrategy(registry)); + this(registry, new RoundRobinStrategy()); } /** * Create a new ClusteredInvoker with the specified load balance strategy. + * @param registry remote registry * @param loadBalancer load balance strategy */ - public ClusteredInvoker(LoadBalanceStrategy loadBalancer) { + public ClusteredInvoker(RemoteRegistry registry, LoadBalanceStrategy loadBalancer) { _loadBalancer = loadBalancer; + _loadBalancer.setRegistry(registry); } - + @Override public void invoke(Exchange exchange) throws SwitchYardException { RemoteEndpoint ep = _loadBalancer.selectEndpoint(exchange.getProvider().getName()); diff --git a/remote/src/main/java/org/switchyard/remote/cluster/LoadBalanceStrategy.java b/remote/src/main/java/org/switchyard/remote/cluster/LoadBalanceStrategy.java index b5c755660..02fcf3544 100644 --- a/remote/src/main/java/org/switchyard/remote/cluster/LoadBalanceStrategy.java +++ b/remote/src/main/java/org/switchyard/remote/cluster/LoadBalanceStrategy.java @@ -43,4 +43,10 @@ public interface LoadBalanceStrategy { * @return remote registry */ RemoteRegistry getRegistry(); + + /** + * Specifies the remote registry used by the load balancing strategy. + * @param registry remote registry + */ + void setRegistry(RemoteRegistry registry); } diff --git a/remote/src/main/java/org/switchyard/remote/cluster/RandomStrategy.java b/remote/src/main/java/org/switchyard/remote/cluster/RandomStrategy.java index e8a92b7e2..b9ee5a5db 100644 --- a/remote/src/main/java/org/switchyard/remote/cluster/RandomStrategy.java +++ b/remote/src/main/java/org/switchyard/remote/cluster/RandomStrategy.java @@ -24,7 +24,6 @@ import javax.xml.namespace.QName; import org.switchyard.remote.RemoteEndpoint; -import org.switchyard.remote.RemoteRegistry; /** * Random endpoint selection strategy which uses a Java Random with default seed to select an @@ -36,10 +35,9 @@ public class RandomStrategy extends BaseStrategy { /** * Create a new RandomStrategy. - * @param registry remote registry */ - public RandomStrategy(RemoteRegistry registry) { - super(registry); + public RandomStrategy() { + super(); } @Override diff --git a/remote/src/main/java/org/switchyard/remote/cluster/RoundRobinStrategy.java b/remote/src/main/java/org/switchyard/remote/cluster/RoundRobinStrategy.java index 296976ac1..31dddabb8 100644 --- a/remote/src/main/java/org/switchyard/remote/cluster/RoundRobinStrategy.java +++ b/remote/src/main/java/org/switchyard/remote/cluster/RoundRobinStrategy.java @@ -23,7 +23,6 @@ import javax.xml.namespace.QName; import org.switchyard.remote.RemoteEndpoint; -import org.switchyard.remote.RemoteRegistry; /** * Round Robin load balancing strategy. The algorithm used here is pretty naive in that the @@ -38,10 +37,9 @@ public class RoundRobinStrategy extends BaseStrategy { /** * Create a new RoundRobin strategy. - * @param registry remote registry */ - public RoundRobinStrategy(RemoteRegistry registry) { - super(registry); + public RoundRobinStrategy() { + super(); } @Override diff --git a/remote/src/main/java/org/switchyard/remote/http/HttpInvoker.java b/remote/src/main/java/org/switchyard/remote/http/HttpInvoker.java index 18867744e..87bc5db34 100644 --- a/remote/src/main/java/org/switchyard/remote/http/HttpInvoker.java +++ b/remote/src/main/java/org/switchyard/remote/http/HttpInvoker.java @@ -28,15 +28,11 @@ import org.switchyard.Exchange; import org.switchyard.ExchangePattern; import org.switchyard.Message; -import org.switchyard.Property; -import org.switchyard.Scope; -import org.switchyard.internal.DefaultContext; import org.switchyard.remote.RemoteInvoker; import org.switchyard.remote.RemoteMessage; import org.switchyard.serial.FormatType; import org.switchyard.serial.Serializer; import org.switchyard.serial.SerializerFactory; -import org.switchyard.transform.TransformSequence; /** * Remote service invoker which uses HTTP as a transport. @@ -114,8 +110,10 @@ public RemoteMessage invoke(RemoteMessage request) throws java.io.IOException { OutputStream os = conn.getOutputStream(); // Sanitize context properties - Context ctx = cloneContext(request.getContext()); - request.setContext(ctx); + if (request.getContext() != null) { + Context ctx = request.getContext().copy(); + request.setContext(ctx); + } // Write the request message _serializer.serialize(request, RemoteMessage.class, os); @@ -133,27 +131,6 @@ public RemoteMessage invoke(RemoteMessage request) throws java.io.IOException { return reply; } - // Remove troublesome context properties from remote message. - private Context cloneContext(Context context) { - Context newCtx = new DefaultContext(); - // return empty context if context to clone is null - if (context == null) { - return newCtx; - } - - newCtx.setProperties(context.getProperties()); - Property inTransform = newCtx.getProperty(TransformSequence.class.getName(), Scope.IN); - Property outTransform = newCtx.getProperty(TransformSequence.class.getName(), Scope.OUT); - if (inTransform != null) { - newCtx.removeProperty(inTransform); - } - if (outTransform != null) { - newCtx.removeProperty(outTransform); - } - - return newCtx; - } - private boolean isInOut(Exchange exchange) { return ExchangePattern.IN_OUT.equals( exchange.getContract().getConsumerOperation().getExchangePattern()); diff --git a/remote/src/test/java/org/switchyard/remote/cluster/RandomStrategyTest.java b/remote/src/test/java/org/switchyard/remote/cluster/RandomStrategyTest.java index 8f025ffa4..060d8c1dc 100644 --- a/remote/src/test/java/org/switchyard/remote/cluster/RandomStrategyTest.java +++ b/remote/src/test/java/org/switchyard/remote/cluster/RandomStrategyTest.java @@ -26,6 +26,7 @@ import junit.framework.Assert; +import org.junit.Before; import org.junit.Test; import org.switchyard.remote.RemoteEndpoint; import org.switchyard.remote.RemoteRegistry; @@ -34,7 +35,12 @@ public class RandomStrategyTest { private static final QName TEST_SERVICE = new QName("RandomStrategy"); private RemoteRegistry registry = new MockRegistry(); - private RandomStrategy random = new RandomStrategy(registry); + private RandomStrategy random = new RandomStrategy(); + + @Before + public void setUp() throws Exception { + random.setRegistry(registry); + } @Test public void noEndpoints() { diff --git a/remote/src/test/java/org/switchyard/remote/cluster/RoundRobinStrategyTest.java b/remote/src/test/java/org/switchyard/remote/cluster/RoundRobinStrategyTest.java index bed4ff2ca..8a132cc2e 100644 --- a/remote/src/test/java/org/switchyard/remote/cluster/RoundRobinStrategyTest.java +++ b/remote/src/test/java/org/switchyard/remote/cluster/RoundRobinStrategyTest.java @@ -22,6 +22,7 @@ import junit.framework.Assert; +import org.junit.Before; import org.junit.Test; import org.switchyard.remote.RemoteEndpoint; import org.switchyard.remote.RemoteRegistry; @@ -30,8 +31,13 @@ public class RoundRobinStrategyTest { private static final QName TEST_SERVICE = new QName("RoundRobinStrategy"); private RemoteRegistry registry = new MockRegistry(); - private RoundRobinStrategy robin = new RoundRobinStrategy(registry); + private RoundRobinStrategy robin = new RoundRobinStrategy(); + @Before + public void setUp() throws Exception { + robin.setRegistry(registry); + } + @Test public void noEndpoints() { Assert.assertNull(robin.selectEndpoint(TEST_SERVICE)); diff --git a/runtime/src/main/java/org/switchyard/handlers/TransactionHandler.java b/runtime/src/main/java/org/switchyard/handlers/TransactionHandler.java index b4852e317..a4235fedd 100644 --- a/runtime/src/main/java/org/switchyard/handlers/TransactionHandler.java +++ b/runtime/src/main/java/org/switchyard/handlers/TransactionHandler.java @@ -29,6 +29,7 @@ import org.switchyard.Exchange; import org.switchyard.ExchangeHandler; import org.switchyard.HandlerException; +import org.switchyard.Labels; import org.switchyard.Property; import org.switchyard.policy.PolicyUtil; import org.switchyard.policy.TransactionPolicy; @@ -77,7 +78,7 @@ public void handleMessage(Exchange exchange) throws HandlerException { // OUT phase in IN_OUT exchange or 2nd invocation in IN_ONLY exchange handleAfter(exchange); } else { - exchange.getContext().setProperty(BEFORE_INVOKED_PROPERTY, Boolean.TRUE); + exchange.getContext().setProperty(BEFORE_INVOKED_PROPERTY, Boolean.TRUE).addLabels(Labels.TRANSIENT); handleBefore(exchange); } } @@ -271,7 +272,7 @@ private void startTransaction(Exchange exchange) throws HandlerException { } catch (Exception e) { throw new HandlerException("Failed to create new transaction", e); } - exchange.getContext().setProperty(INITIATED_TRANSACTION_PROPERTY, transaction); + exchange.getContext().setProperty(INITIATED_TRANSACTION_PROPERTY, transaction).addLabels(Labels.TRANSIENT); } else { throw new HandlerException("Transaction already exists"); } @@ -314,7 +315,7 @@ private void suspendTransaction(Exchange exchange) { _log.error("Failed to suspend transaction on exchange.", sysEx); } if (transaction != null) { - exchange.getContext().setProperty(SUSPENDED_TRANSACTION_PROPERTY, transaction); + exchange.getContext().setProperty(SUSPENDED_TRANSACTION_PROPERTY, transaction).addLabels(Labels.TRANSIENT); } } diff --git a/runtime/src/main/java/org/switchyard/handlers/TransformHandler.java b/runtime/src/main/java/org/switchyard/handlers/TransformHandler.java index 7d2700d2d..571b4fdca 100644 --- a/runtime/src/main/java/org/switchyard/handlers/TransformHandler.java +++ b/runtime/src/main/java/org/switchyard/handlers/TransformHandler.java @@ -29,6 +29,7 @@ import org.switchyard.Exchange; import org.switchyard.ExchangePhase; import org.switchyard.HandlerException; +import org.switchyard.Labels; import org.switchyard.Property; import org.switchyard.Scope; import org.switchyard.internal.transform.BaseTransformerRegistry; @@ -124,7 +125,7 @@ public void handleFault(Exchange exchange) { private void setContentType(Exchange exchange) { QName currentType = TransformSequence.getCurrentMessageType(exchange); if (currentType != null) { - exchange.getContext().setProperty(Exchange.CONTENT_TYPE, currentType, Scope.activeScope(exchange)); + exchange.getContext().setProperty(Exchange.CONTENT_TYPE, currentType, Scope.activeScope(exchange)).addLabels(Labels.TRANSIENT); } else { // make sure no property is used for current scope Property p = exchange.getContext().getProperty(Exchange.CONTENT_TYPE, Scope.activeScope(exchange)); diff --git a/runtime/src/main/java/org/switchyard/handlers/ValidateHandler.java b/runtime/src/main/java/org/switchyard/handlers/ValidateHandler.java index 790543972..d12318217 100644 --- a/runtime/src/main/java/org/switchyard/handlers/ValidateHandler.java +++ b/runtime/src/main/java/org/switchyard/handlers/ValidateHandler.java @@ -25,6 +25,7 @@ import org.switchyard.BaseHandler; import org.switchyard.Exchange; import org.switchyard.HandlerException; +import org.switchyard.Labels; import org.switchyard.Message; import org.switchyard.Property; import org.switchyard.Scope; @@ -124,7 +125,8 @@ private boolean applyValidator(Exchange exchange, Validator validator) { + ") with name '" + validator.getName() + "' using validator type '" + validator.getType() + "'."); } } - exchange.getContext().setProperty(KEY_VALIDATED_TYPE, validator.getType(), Scope.activeScope(exchange)); + exchange.getContext().setProperty( + KEY_VALIDATED_TYPE, validator.getType(), Scope.activeScope(exchange)).addLabels(Labels.TRANSIENT); return validated; } } diff --git a/runtime/src/main/java/org/switchyard/internal/DefaultContext.java b/runtime/src/main/java/org/switchyard/internal/DefaultContext.java index 7d795fff9..4d411f0ae 100644 --- a/runtime/src/main/java/org/switchyard/internal/DefaultContext.java +++ b/runtime/src/main/java/org/switchyard/internal/DefaultContext.java @@ -19,9 +19,11 @@ package org.switchyard.internal; +import java.util.HashSet; import java.util.Set; import org.switchyard.Context; +import org.switchyard.Labels; import org.switchyard.Property; import org.switchyard.Scope; import org.switchyard.serial.graph.AccessType; @@ -117,13 +119,30 @@ public Property setProperty(String name, Object val) { return p; } - /** - * Provides a shallow copy of the context so that additions and removals - * to the copied reference are not reflected in the original (and vice - * versa, natch). - * @return shallow copy of this context - */ - public DefaultContext copy() { - return new DefaultContext(_properties.copy()); + @Override + public Context copy() { + Context ctx = new DefaultContext(_properties.copy()); + ctx.removeProperties(Labels.TRANSIENT); + return ctx; + } + + @Override + public Set getProperties(String label) { + Set props = new HashSet(); + for (Property p : getProperties()) { + if (p.hasLabel(label)) { + props.add(p); + } + } + return props; + } + + @Override + public void removeProperties(String label) { + for (Property p : getProperties()) { + if (p.hasLabel(label)) { + removeProperty(p); + } + } } } diff --git a/runtime/src/main/java/org/switchyard/internal/ExchangeImpl.java b/runtime/src/main/java/org/switchyard/internal/ExchangeImpl.java index 314abe694..bc0484122 100644 --- a/runtime/src/main/java/org/switchyard/internal/ExchangeImpl.java +++ b/runtime/src/main/java/org/switchyard/internal/ExchangeImpl.java @@ -31,6 +31,7 @@ import org.switchyard.ExchangePattern; import org.switchyard.ExchangePhase; import org.switchyard.ExchangeState; +import org.switchyard.Labels; import org.switchyard.Message; import org.switchyard.Scope; import org.switchyard.Service; @@ -113,7 +114,7 @@ public synchronized void send(Message message) { initOutContentType(); // set relatesTo header on OUT context _context.setProperty(RELATES_TO, _context.getProperty( - MESSAGE_ID, Scope.IN).getValue(), Scope.OUT); + MESSAGE_ID, Scope.IN).getValue(), Scope.OUT).addLabels(Labels.TRANSIENT); } else { throw new IllegalStateException( "Send message not allowed for exchange in phase " + _phase); @@ -137,7 +138,7 @@ public synchronized void sendFault(Message message) { // set relatesTo header on OUT context _context.setProperty(RELATES_TO, _context.getProperty( - MESSAGE_ID, Scope.IN).getValue(), Scope.OUT); + MESSAGE_ID, Scope.IN).getValue(), Scope.OUT).addLabels(Labels.TRANSIENT); sendInternal(message); } @@ -185,7 +186,7 @@ private void sendInternal(Message message) { _message = message; // assign messageId - _context.setProperty(MESSAGE_ID, UUID.randomUUID().toString(), Scope.activeScope(this)); + _context.setProperty(MESSAGE_ID, UUID.randomUUID().toString(), Scope.activeScope(this)).addLabels(Labels.TRANSIENT); if (_log.isDebugEnabled()) { _log.debug("Sending " + _phase + " Message (" + System.identityHashCode(message) + ") on " @@ -219,7 +220,7 @@ private void sendInternal(Message message) { if (isDone(sendPhase)) { long duration = System.nanoTime() - _startTime; getContext().setProperty(ExchangeCompletionEvent.EXCHANGE_DURATION, - TimeUnit.MILLISECONDS.convert(duration, TimeUnit.NANOSECONDS)); + TimeUnit.MILLISECONDS.convert(duration, TimeUnit.NANOSECONDS)).addLabels(Labels.TRANSIENT); _domain.getEventPublisher().publish(new ExchangeCompletionEvent(this)); } } @@ -293,11 +294,15 @@ protected void setPhase(ExchangePhase phase) { _phase = phase; } + protected void setMessage(Message message) { + _message = message; + } + private void initInContentType() { QName exchangeInputType = _contract.getConsumerOperation().getInputType(); if (exchangeInputType != null) { - _context.setProperty(Exchange.CONTENT_TYPE, exchangeInputType, Scope.IN); + _context.setProperty(Exchange.CONTENT_TYPE, exchangeInputType, Scope.IN).addLabels(Labels.TRANSIENT); } } @@ -305,7 +310,7 @@ private void initOutContentType() { QName serviceOperationOutputType = _contract.getProviderOperation().getOutputType(); if (serviceOperationOutputType != null) { - _context.setProperty(Exchange.CONTENT_TYPE, serviceOperationOutputType, Scope.OUT); + _context.setProperty(Exchange.CONTENT_TYPE, serviceOperationOutputType, Scope.OUT).addLabels(Labels.TRANSIENT); } } @@ -313,7 +318,7 @@ private void initFaultContentType() { if (_contract.getProviderOperation() != null) { QName serviceOperationFaultType = _contract.getProviderOperation().getFaultType(); if (serviceOperationFaultType != null) { - _context.setProperty(Exchange.CONTENT_TYPE, serviceOperationFaultType, Scope.OUT); + _context.setProperty(Exchange.CONTENT_TYPE, serviceOperationFaultType, Scope.OUT).addLabels(Labels.TRANSIENT); } } } diff --git a/runtime/src/test/java/org/switchyard/MockExchange.java b/runtime/src/test/java/org/switchyard/MockExchange.java index a3470de3b..406a5a815 100644 --- a/runtime/src/test/java/org/switchyard/MockExchange.java +++ b/runtime/src/test/java/org/switchyard/MockExchange.java @@ -33,4 +33,8 @@ public MockExchange() { public void setPhase(ExchangePhase phase) { super.setPhase(phase); } + + public void setMessage(Message message) { + super.setMessage(message); + } } diff --git a/runtime/src/test/java/org/switchyard/internal/DefaultContextTest.java b/runtime/src/test/java/org/switchyard/internal/DefaultContextTest.java index 7b5c16ff1..6674f9268 100644 --- a/runtime/src/test/java/org/switchyard/internal/DefaultContextTest.java +++ b/runtime/src/test/java/org/switchyard/internal/DefaultContextTest.java @@ -24,6 +24,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.switchyard.Context; +import org.switchyard.Labels; import org.switchyard.Property; import org.switchyard.Scope; @@ -125,12 +127,45 @@ public void testGetProperties() { Assert.assertTrue(_context.getProperties().size() == 1); } + @Test + public void testGetPropertyLabel() { + _context.setProperty("a", "a", Scope.IN).addLabels(Labels.TRANSIENT); + _context.setProperty("b", "b", Scope.OUT).addLabels(Labels.TRANSIENT); + _context.setProperty("c", "c", Scope.EXCHANGE).addLabels(Labels.TRANSIENT); + _context.setProperty("d", "d", Scope.IN).addLabels("foo"); + Assert.assertEquals(3, _context.getProperties(Labels.TRANSIENT).size()); + Assert.assertEquals(1, _context.getProperties("foo").size()); + } + + @Test + public void testRemovePropertyLabel() { + _context.setProperty("a", "a", Scope.IN).addLabels(Labels.TRANSIENT); + _context.setProperty("b", "b", Scope.OUT).addLabels(Labels.TRANSIENT); + _context.setProperty("c", "c", Scope.EXCHANGE).addLabels(Labels.TRANSIENT); + _context.setProperty("d", "d", Scope.IN).addLabels("foo"); + + _context.removeProperties(Labels.TRANSIENT); + Assert.assertEquals(0, _context.getProperties(Labels.TRANSIENT).size()); + Assert.assertEquals(1, _context.getProperties("foo").size()); + } + + @Test + public void testCopyClean() { + _context.setProperty("a", "a", Scope.IN).addLabels(Labels.TRANSIENT); + _context.setProperty("b", "b", Scope.OUT); + _context.setProperty("c", "c", Scope.EXCHANGE).addLabels(Labels.TRANSIENT); + + Context newCtx = _context.copy(); + Assert.assertEquals(0, newCtx.getProperties(Labels.TRANSIENT).size()); + Assert.assertEquals(1, newCtx.getProperties().size()); + } + @Test public void testCopy() { _context.setProperty("exchange", "val", Scope.EXCHANGE); _context.setProperty("in", "val", Scope.IN); _context.setProperty("out", "val", Scope.OUT); - DefaultContext ctx = _context.copy(); + Context ctx = _context.copy(); // verify that all fields were copied Assert.assertEquals( _context.getProperty("exchange", Scope.EXCHANGE),