summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/trunk/modules/core/src/main/java/org/apache
diff options
context:
space:
mode:
authorslaws <slaws@13f79535-47bb-0310-9956-ffa450edef68>2012-02-09 17:46:50 +0000
committerslaws <slaws@13f79535-47bb-0310-9956-ffa450edef68>2012-02-09 17:46:50 +0000
commit59412d176cd4e7950cb48e48580a6de6fb8fec70 (patch)
tree2b41f3020605fe14c7ec709aa9b241dfcd8c7d0d /sca-java-2.x/trunk/modules/core/src/main/java/org/apache
parenta9891d03be69d7daab14d273f3209c178fcb086e (diff)
TUSCANY-4011 - stop the SCDL callback binding configuration from being overwritten. The JMS binding strangely relied on this so required some surgery. I've also simplified CallbackServiceReference and added a CALLBACK message header and CallbackHandler object to make is simpler to pass the callback address down the message chain. The existing approach of creating a CallbackEndpoint model is still supported at the moment.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1242412 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-java-2.x/trunk/modules/core/src/main/java/org/apache')
-rw-r--r--sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java254
-rw-r--r--sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java53
-rw-r--r--sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java1
-rw-r--r--sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java3
4 files changed, 237 insertions, 74 deletions
diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java
index 61f9b7e2cb..b0561303a8 100644
--- a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java
+++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/context/impl/CallbackServiceReferenceImpl.java
@@ -18,8 +18,9 @@
*/
package org.apache.tuscany.sca.core.context.impl;
-import java.net.URI;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.apache.tuscany.sca.assembly.Binding;
import org.apache.tuscany.sca.assembly.Endpoint;
@@ -29,28 +30,86 @@ import org.apache.tuscany.sca.assembly.builder.BindingBuilder;
import org.apache.tuscany.sca.assembly.builder.BuilderContext;
import org.apache.tuscany.sca.context.CompositeContext;
import org.apache.tuscany.sca.context.ThreadMessageContext;
+import org.apache.tuscany.sca.core.invocation.CallbackHandler;
import org.apache.tuscany.sca.core.invocation.Constants;
import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
import org.oasisopen.sca.ServiceRuntimeException;
+/**
+ * Represent the reference to the callback service. This class basically wraps a Tuscany EndpointReference.
+ * The callback EPR is selected based on the are 3 basic scenarios we are trying to cater for
+ *
+ * A/ <component name="MyComponent">
+ * <service name="MyService>
+ * blank OR <binding.sca/>
+ * </service>
+ * </component>
+ *
+ * B/ <component name="MyComponent">
+ * <service name="MyService>
+ * <binding.someremotebinding/>
+ * </service>
+ * </component>
+ *
+ * C/ <component name="MyComponent">
+ * <service name="MyService>
+ * some binding
+ * <callback>
+ * <binding.someremotebinding/>
+ * </callback>
+ * </service>
+ * </component>
+ *
+ * A - the callback binding will default to binding.sca and the expectation is that
+ * the callback endpoint will be established by looking it up in the registry
+ * hence the forward call must contain the SCA target name referring to the
+ * callback service
+ *
+ * B - the callback binding defaults to be the forward binding taking all of its
+ * configuration. The callback target URI is taken from the forward message and
+ * put into the callback binding URI
+ *
+ * C - the callback binding is as specified by the user. If the user has not specified
+ * a binding URI then the URI from the forward message will be placed in the
+ * callback binding URI. This may or may not lead to happiness depending on whether
+ * the forward and callback bindings are compatible
+ *
+ * The callback proxy, and this class, is instantiated whenever a new callback proxy is
+ * required as follows:
+ *
+ * If the service component implementation is STATELESS then each incoming message
+ * creates a new service instance and hence a new set of callback proxies
+ *
+ * If the service component implementation is COMPOSITE then only a single instance
+ * of the component implementation will exist and the callback proxy will be retrieved
+ * via the RequestContext.
+ *
+ * Following the Tuscany runtime model for normal references we don't cache callback
+ * proxies across component implementation instances. Hence there will be one
+ * instance of this class for each callback proxy, however created, and the class
+ * will refer to a single callback service. To put it another way, messages from
+ * multiple clients (presenting different callback services) will be called back to
+ * via different callback proxies and hence a single instance of this class will
+ * not be required to handle more than one callback address.
+ *
+ */
public class CallbackServiceReferenceImpl<B> extends ServiceReferenceImpl<B> {
+ private static final Logger logger = Logger.getLogger(CallbackServiceReferenceImpl.class.getName());
private RuntimeEndpointReference callbackEPR;
private List<? extends EndpointReference> callbackEPRs;
private Endpoint resolvedEndpoint;
// Holds the ID of the Message that caused the creation of this CallbackServiceReference
private String msgID;
-
- /**
- * Gets the message ID associated with this callback reference
- * @return the message ID
- */
- public String getMsgID() {
- return msgID;
- }
+
+ // Holds the URI of the target callback service from the Message that caused the
+ // creation of this CallbackServiceReference
+ private CallbackHandler callbackHandler;
/*
* Public constructor for Externalizable serialization/deserialization
+ * TODO - we need to serialize the msgID and callbackURI
*/
public CallbackServiceReferenceImpl() {
super();
@@ -60,9 +119,69 @@ public class CallbackServiceReferenceImpl<B> extends ServiceReferenceImpl<B> {
List<? extends EndpointReference> callbackEPRs) {
super(interfaze, null, getCompositeContext(callbackEPRs));
this.callbackEPRs = callbackEPRs;
- init();
+
+ Message msgContext = ThreadMessageContext.getMessageContext();
+
+ // Capture the Message ID from the message which caused the creation of this
+ // CallBackServiceReference
+ this.msgID = (String) msgContext.getHeaders().get(Constants.MESSAGE_ID);
+
+ // Capture the callback URI from the message which caused the creation of this
+ // CallBackServiceReference. This code is more complex that needs be for the time being
+ // to cater for bindings that still use the approach of constructing a callback endpoint
+ // to model the callback URI. With these changes the binding can just set a CallbackHandler
+ // in the forward message to get the same effect. Some bindings don't do that hence
+ // the various checks
+ this.resolvedEndpoint = msgContext.getFrom().getCallbackEndpoint();
+ if (resolvedEndpoint != null && resolvedEndpoint.getBinding() != null){
+ if (resolvedEndpoint.getBinding().getType().equals(SCABinding.TYPE)){
+ this.callbackHandler = new CallbackHandler(resolvedEndpoint.getURI());
+ } else {
+ this.callbackHandler = new CallbackHandler(resolvedEndpoint.getBinding().getURI());
+ }
+ } else {
+ this.callbackHandler = (CallbackHandler)msgContext.getHeaders().get(Constants.CALLBACK);
+
+ if (callbackHandler == null){
+ this.callbackHandler = new CallbackHandler(null);
+ }
+ }
+
+ if (callbackHandler.getCallbackTargetURI() != null){
+ logger.log(Level.FINE, "Selecting callback EPR using address from forward message: " + callbackHandler.getCallbackTargetURI());
+ } else {
+ logger.log(Level.FINE, "Selecting callback EPR using address but callback URI is null");
+ }
+
+ // Work out which callback EPR to use
+ callbackEPR = selectCallbackEPR(msgContext);
+ if (callbackEPR == null) {
+ throw new ServiceRuntimeException("No callback binding found for " + msgContext.getTo().toString());
+ }
+
+ // configure the callback EPR with the callback address
+ if (callbackHandler.getCallbackTargetURI() != null) {
+ callbackEPR = setCallbackAddress(callbackEPR);
+ }
+
+ this.resolvedEndpoint = callbackEPR.getTargetEndpoint();
+ }
+
+ public CallbackHandler getCallbackHandler() {
+ return callbackHandler;
}
+ /**
+ * Gets the message ID associated with this callback reference. All calls through the proxy backed by
+ * this CallbackServiceReference will use the same msgID
+ *
+ * @return the message ID
+ */
+ public String getMsgID() {
+ return msgID;
+ }
+
+
private static CompositeContext getCompositeContext(List<? extends EndpointReference> callbackEPRs) {
if(!callbackEPRs.isEmpty()) {
RuntimeEndpointReference epr = (RuntimeEndpointReference) callbackEPRs.get(0);
@@ -71,29 +190,13 @@ public class CallbackServiceReferenceImpl<B> extends ServiceReferenceImpl<B> {
return null;
}
- public void init() {
- Message msgContext = ThreadMessageContext.getMessageContext();
- callbackEPR = selectCallbackEPR(msgContext);
- if (callbackEPR == null) {
- throw new ServiceRuntimeException("No callback binding found for " + msgContext.getTo().toString());
- }
- resolvedEndpoint = msgContext.getFrom().getCallbackEndpoint();
-
- // Capture the Message ID from the message which caused the creation of this CallBackServiceReference
- this.msgID = (String) msgContext.getHeaders().get(Constants.MESSAGE_ID);
- }
-
@Override
protected B createProxy() throws Exception {
return proxyFactory.createCallbackProxy(this);
}
public RuntimeEndpointReference getCallbackEPR() {
- if (resolvedEndpoint == null) {
- return null;
- } else {
- return cloneAndBind(callbackEPR);
- }
+ return callbackEPR;
}
public Endpoint getResolvedEndpoint() {
@@ -101,6 +204,7 @@ public class CallbackServiceReferenceImpl<B> extends ServiceReferenceImpl<B> {
}
private RuntimeEndpointReference selectCallbackEPR(Message msgContext) {
+
// look for callback binding with same name as service binding
Endpoint to = msgContext.getTo();
if (to == null) {
@@ -124,56 +228,58 @@ public class CallbackServiceReferenceImpl<B> extends ServiceReferenceImpl<B> {
return null;
}
- private RuntimeEndpointReference cloneAndBind(RuntimeEndpointReference endpointReference) {
- if (resolvedEndpoint != null) {
-
- try {
- RuntimeEndpointReference epr = (RuntimeEndpointReference)endpointReference.clone();
- epr.setTargetEndpoint(resolvedEndpoint);
+ private RuntimeEndpointReference setCallbackAddress(RuntimeEndpointReference endpointReference) {
+ try {
+
+ RuntimeEndpointReference epr = endpointReference;
+
+ if (callbackHandler.getCloneCallbackWire()){
+ epr = (RuntimeEndpointReference)endpointReference.clone();
+ }
+
+ // TUSCANY-3932
+ // If it's the default binding then we're going to look the callback endpoint
+ // up in the registry. Most remote protocols, which may be used as delegates
+ // for binding.sca, will expect to deal with absolute URLs so flip the
+ // callback endpoint back to force the lookup to happen
+ if (epr.getBinding().getType().equals(SCABinding.TYPE)){
+ // A/ create a callback endpoint to allow the
+ // callback lookup to take place
+ epr.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND);
+
+ // if an endpoint it provided in the forward message use it or
+ // if not create one
+ if (resolvedEndpoint == null ){
+ RuntimeEndpoint callbackEndpoint = (RuntimeEndpoint)assemblyFactory.createEndpoint();
+ callbackEndpoint.setURI(callbackHandler.getCallbackTargetURI());
+ callbackEndpoint.setUnresolved(true);
+ epr.setTargetEndpoint(callbackEndpoint);
+ } else {
+ epr.setTargetEndpoint(resolvedEndpoint);
+ }
+ } else {
+ // B/ and C/ assume that the callback EPR is already resolved
+ // and set the binding URI if one is provided with the
+ // forward message. Some bindings may want to do other
+ // things to determine the callback URI to the
+ // CallbackHandler will be sent in the callback message
+ // header. This is particularly true if the clone isn't
+ // called above because resetting the URI will not
+ // be thread safe.
+ epr.setStatus(EndpointReference.Status.RESOLVED_BINDING);
- // TUSCANY-3932
- // If it's the default binding then we're going to look the callback endpoint
- // up in the registry. Most remote protocols, which may be used as delegates
- // for binding.sca, will expect to deal with absolute URLs so flip the
- // callback endpoint back to force the lookup to happen
- if (epr.getBinding().getType().equals(SCABinding.TYPE)){
- epr.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND);
+ if ( callbackHandler.getCallbackTargetURI() != null ){
+ epr.getBinding().setURI(callbackHandler.getCallbackTargetURI());
} else {
- // just copy the callback binding from the callback endpoint to the
- // callback EPR as the EPR is effectively already resolved
- epr.setStatus(EndpointReference.Status.RESOLVED_BINDING);
- Binding callbackBinding = resolvedEndpoint.getBinding();
- if ( callbackBinding != null){
- epr.setBinding(callbackBinding);
- // make sure that the chains are recreated for
- // this new binding
- epr.setBindingProvider(null);
- epr.rebuild();
- } else {
- // do nothing and rely on whatever the user has configured
- // in the SCDL
- }
+ // do nothing and rely on whatever the user has configured
+ // in the SCDL
}
-
- return epr;
- } catch (CloneNotSupportedException e) {
- // will not happen
- throw new ServiceRuntimeException(e);
}
- } else {
- return null;
- }
- }
-
- private void build(EndpointReference endpointReference) {
- BindingBuilder builder = builders.getBindingBuilder(endpointReference.getBinding().getType());
- if (builder != null) {
- builder.build(endpointReference.getComponent(),
- endpointReference.getReference(),
- endpointReference.getBinding(),
- new BuilderContext(registry),
- false);
+
+ return epr;
+ } catch (CloneNotSupportedException e) {
+ // will not happen
+ throw new ServiceRuntimeException(e);
}
- }
-
+ }
}
diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java
new file mode 100644
index 0000000000..bccce0d20a
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackHandler.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.core.invocation;
+
+/**
+ * Models callback information arriving in the forward message
+ */
+public class CallbackHandler {
+ private String callbackTargetURI;
+ private boolean cloneCallbackWire = true;
+
+ public CallbackHandler(String callbackTargetURI){
+ setCallbackTargetURI(callbackTargetURI);
+ }
+
+ public CallbackHandler(String callbackTargetURI, boolean cloneCallbackWire){
+ setCallbackTargetURI(callbackTargetURI);
+ setCloneCallbackWire(cloneCallbackWire);
+ }
+
+ public String getCallbackTargetURI() {
+ return callbackTargetURI;
+ }
+
+ public boolean getCloneCallbackWire() {
+ return cloneCallbackWire;
+ }
+
+ public void setCallbackTargetURI(String callbackTargetURI) {
+ this.callbackTargetURI = callbackTargetURI;
+ }
+
+ public void setCloneCallbackWire(boolean cloneCallbackWire) {
+ this.cloneCallbackWire = cloneCallbackWire;
+ }
+}
diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java
index d84ef752ac..00c650ada6 100644
--- a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java
+++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/Constants.java
@@ -28,6 +28,7 @@ public interface Constants {
public static final String RELATES_TO = "RELATES_TO";
public static final String ASYNC_RESPONSE_INVOKER = "ASYNC_RESPONSE_INVOKER";
public static final String ASYNC_CALLBACK = "ASYNC_CALLBACK";
+ public static final String CALLBACK = "CALLBACK";
/**
* If you've set the TCCL in your binding impl according to OASIS rules you can prevent
diff --git a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java
index c35b70ad74..bde3e92c27 100644
--- a/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java
+++ b/sca-java-2.x/trunk/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/impl/JDKCallbackInvocationHandler.java
@@ -105,6 +105,9 @@ public class JDKCallbackInvocationHandler extends JDKInvocationHandler {
msg.setTo(((RuntimeEndpointReference)source).getTargetEndpoint());
}
}
+
+ msg.getHeaders().put(Constants.CALLBACK, ((CallbackServiceReferenceImpl)callableReference).getCallbackHandler());
+
Invoker headInvoker = chain.getHeadInvoker();
Operation operation = null;