diff options
author | slaws <slaws@13f79535-47bb-0310-9956-ffa450edef68> | 2010-02-12 13:01:03 +0000 |
---|---|---|
committer | slaws <slaws@13f79535-47bb-0310-9956-ffa450edef68> | 2010-02-12 13:01:03 +0000 |
commit | 3739ece0a0cdb420cff1a5d7cd80d45bb6de1bef (patch) | |
tree | 752fe6d1bb12d04da9c4c57635bcfe178b1f32d3 /sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src | |
parent | 7e1bbf11b260df1e5b35954213022234e8e5768a (diff) |
Enable reference side binding wire. Mainly so I can start trying out some binding specific policy implementations.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@909388 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src')
-rw-r--r-- | sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2OneWayBindingInvoker.java | 66 | ||||
-rw-r--r-- | sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2ReferenceBindingProvider.java | 40 | ||||
-rw-r--r-- | sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/provider/Axis2BindingInvoker.java (renamed from sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2BindingInvoker.java) | 142 | ||||
-rw-r--r-- | sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/TransportReferenceInterceptor.java | 137 |
4 files changed, 187 insertions, 198 deletions
diff --git a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2OneWayBindingInvoker.java b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2OneWayBindingInvoker.java deleted file mode 100644 index 4a22b39ed9..0000000000 --- a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2OneWayBindingInvoker.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.binding.ws.axis2; - -import javax.xml.namespace.QName; - -import org.apache.axiom.soap.SOAPFactory; -import org.apache.axis2.AxisFault; -import org.apache.axis2.client.OperationClient; -import org.apache.axis2.client.Options; -import org.apache.axis2.context.MessageContext; -import org.apache.axis2.transport.http.HTTPConstants; -import org.apache.tuscany.sca.binding.ws.WebServiceBinding; -import org.apache.tuscany.sca.invocation.Message; - -/** - * Axis2OneWayBindingInvoker uses an Axis2 OperationClient to invoke a OneWay remote web service. - * - * @version $Rev$ $Date$ - */ -public class Axis2OneWayBindingInvoker extends Axis2BindingInvoker { - - public Axis2OneWayBindingInvoker(Axis2ReferenceBindingProvider bindingProvider, - QName wsdlOperationName, - Options options, - SOAPFactory soapFactory, - WebServiceBinding wsBinding) { - - super(bindingProvider, wsdlOperationName, options, soapFactory, wsBinding); - } - - @Override - protected Object invokeTarget(Message msg) throws AxisFault { - OperationClient operationClient = createOperationClient(msg); - - // ensure connections are tracked so that they can be closed by the reference binding - MessageContext requestMC = operationClient.getMessageContext("Out"); - //requestMC.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); - Options opt = requestMC.getOptions(); - opt.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); - opt.setUseSeparateListener(true); - opt.setProperty(HTTPConstants.AUTO_RELEASE_CONNECTION,Boolean.TRUE); - - operationClient.execute(false); - - // REVIEW it seems ok to return null - return null; - } - -} diff --git a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2ReferenceBindingProvider.java b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2ReferenceBindingProvider.java index 15e4ea3435..8a5aab0ac6 100644 --- a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2ReferenceBindingProvider.java +++ b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2ReferenceBindingProvider.java @@ -55,21 +55,26 @@ import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.tuscany.sca.assembly.EndpointReference; import org.apache.tuscany.sca.assembly.xml.Constants; +import org.apache.tuscany.sca.binding.ws.axis2.transport.TransportReferenceInterceptor; import org.apache.tuscany.sca.binding.ws.WebServiceBinding; +import org.apache.tuscany.sca.binding.ws.axis2.provider.Axis2BindingInvoker; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.FactoryExtensionPoint; -import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.invocation.Phase; import org.apache.tuscany.sca.policy.util.PolicyHelper; +import org.apache.tuscany.sca.provider.EndpointReferenceProvider; import org.apache.tuscany.sca.provider.ReferenceBindingProvider; import org.apache.tuscany.sca.runtime.RuntimeComponent; import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; import org.oasisopen.sca.ServiceRuntimeException; -public class Axis2ReferenceBindingProvider implements ReferenceBindingProvider { +public class Axis2ReferenceBindingProvider implements EndpointReferenceProvider { // Tuscany extensions private ExtensionPointRegistry extensionPoints; @@ -78,7 +83,7 @@ public class Axis2ReferenceBindingProvider implements ReferenceBindingProvider { // the endpoint reference configuration that's driving this binding provider // and some convenience data retrieved from the endpoint reference - private EndpointReference endpointReference; + private RuntimeEndpointReference endpointReference; private RuntimeComponent component; private RuntimeComponentReference reference; private WebServiceBinding wsBinding; @@ -99,7 +104,7 @@ public class Axis2ReferenceBindingProvider implements ReferenceBindingProvider { EndpointReference endpointReference) { this.extensionPoints = extensionPoints; - this.endpointReference = endpointReference; + this.endpointReference = (RuntimeEndpointReference)endpointReference; this.modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); this.messageFactory = modelFactories.getFactory(MessageFactory.class); @@ -202,6 +207,7 @@ public class Axis2ReferenceBindingProvider implements ReferenceBindingProvider { public InterfaceContract getBindingInterfaceContract() { return wsBinding.getBindingInterfaceContract(); + } public boolean supportsOneWayInvocation() { @@ -241,14 +247,31 @@ public class Axis2ReferenceBindingProvider implements ReferenceBindingProvider { { options.setProperty(org.apache.axis2.Constants.Configuration.ENABLE_MTOM, org.apache.axis2.Constants.VALUE_TRUE); } - Axis2BindingInvoker invoker; + + return new Axis2BindingInvoker(endpointReference, serviceClient, wsdlOperationQName, options, soapFactory, wsBinding); + +/* if (operation.isNonBlocking()) { invoker = new Axis2OneWayBindingInvoker(this, wsdlOperationQName, options, soapFactory, wsBinding); } else { - invoker = new Axis2BindingInvoker(this, wsdlOperationQName, options, soapFactory, wsBinding); + invoker = new Axis2BindingInvoker(endpointReference, serviceClient, wsdlOperationQName, options, soapFactory, wsBinding); } return invoker; +*/ + } + + /* + * set up the reference binding wire with the right set of ws reference + * interceptors + */ + public void configure() { + InvocationChain bindingChain = endpointReference.getBindingInvocationChain(); + + // add transport interceptor + bindingChain.addInterceptor(Phase.REFERENCE_BINDING_TRANSPORT, + new TransportReferenceInterceptor()); + } // Reference specific utility operations @@ -326,9 +349,4 @@ public class Axis2ReferenceBindingProvider implements ReferenceBindingProvider { } return null; } - - public ServiceClient getServiceClient() { - return serviceClient; - } - } diff --git a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2BindingInvoker.java b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/provider/Axis2BindingInvoker.java index fd18997adc..dd5a49d4dd 100644 --- a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/Axis2BindingInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/provider/Axis2BindingInvoker.java @@ -16,13 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.tuscany.sca.binding.ws.axis2; +package org.apache.tuscany.sca.binding.ws.axis2.provider; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.List; import javax.xml.namespace.QName; @@ -37,83 +35,56 @@ import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.addressing.EndpointReferenceHelper; import org.apache.axis2.client.OperationClient; import org.apache.axis2.client.Options; +import org.apache.axis2.client.ServiceClient; import org.apache.axis2.context.MessageContext; -import org.apache.axis2.transport.http.HTTPConstants; import org.apache.tuscany.sca.assembly.Endpoint; import org.apache.tuscany.sca.binding.ws.WebServiceBinding; import org.apache.tuscany.sca.interfacedef.util.FaultException; import org.apache.tuscany.sca.invocation.DataExchangeSemantics; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.Message; -import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; /** - * Axis2BindingInvoker uses an Axis2 OperationClient to invoke a remote web service + * Axis2BindingInvoker creates an Axis2 OperationClient to pass down the + * binding chain * * @version $Rev$ $Date$ */ public class Axis2BindingInvoker implements Invoker, DataExchangeSemantics { - private final static String SCA11_TUSCANY_NS = "http://tuscany.apache.org/xmlns/sca/1.1"; - public static final QName QNAME_WSA_FROM = - new QName(AddressingConstants.Final.WSA_NAMESPACE, AddressingConstants.WSA_FROM, + new QName(AddressingConstants.Final.WSA_NAMESPACE, + AddressingConstants.WSA_FROM, AddressingConstants.WSA_DEFAULT_PREFIX); - public static final String TUSCANY_PREFIX = "tuscany"; - public static final QName CALLBACK_ID_REFPARM_QN = - new QName(SCA11_TUSCANY_NS, "CallbackID", TUSCANY_PREFIX); - public static final QName CONVERSATION_ID_REFPARM_QN = - new QName(SCA11_TUSCANY_NS, "ConversationID", TUSCANY_PREFIX); - private Axis2ReferenceBindingProvider bindingProvider; + private RuntimeEndpointReference endpointReference; + private ServiceClient serviceClient; private QName wsdlOperationName; private Options options; private SOAPFactory soapFactory; private WebServiceBinding wsBinding; -// private BasicAuthenticationPolicy basicAuthenticationPolicy = null; -// private Axis2TokenAuthenticationPolicy axis2TokenAuthenticationPolicy = null; -// private List<Axis2HeaderPolicy> axis2HeaderPolicies = new ArrayList<Axis2HeaderPolicy>(); - - public Axis2BindingInvoker(Axis2ReferenceBindingProvider bindingProvider, + public Axis2BindingInvoker(RuntimeEndpointReference endpointReference, + ServiceClient serviceClient, QName wsdlOperationName, Options options, SOAPFactory soapFactory, WebServiceBinding wsBinding) { - this.bindingProvider = bindingProvider; + this.endpointReference = endpointReference; + this.serviceClient = serviceClient; this.wsdlOperationName = wsdlOperationName; this.options = options; this.soapFactory = soapFactory; this.wsBinding = wsBinding; - - // find out which policies are active - /* - if (wsBinding instanceof PolicySubject) { - List<PolicySet> policySets = ((PolicySubject)wsBinding).getPolicySets(); - for (PolicySet ps : policySets) { - for (Object p : ps.getPolicies()) { - if (BasicAuthenticationPolicy.class.isInstance(p)) { - basicAuthenticationPolicy = (BasicAuthenticationPolicy)p; - } else if (Axis2TokenAuthenticationPolicy.class.isInstance(p)) { - axis2TokenAuthenticationPolicy = (Axis2TokenAuthenticationPolicy)p; - } else if (Axis2HeaderPolicy.class.isInstance(p)) { - axis2HeaderPolicies.add((Axis2HeaderPolicy)p); - }else { - // etc. check for other types of policy being present - } - } - } - } - */ } - - private static final QName EXCEPTION = new QName("", "Exception"); - + public Message invoke(Message msg) { try { - Object resp = invokeTarget(msg); - - msg.setBody(resp); + final OperationClient operationClient = createOperationClient(msg); + msg.setBindingContext(operationClient); + msg = endpointReference.getBindingInvocationChain().getHeadInvoker().invoke(msg); + } catch (AxisFault e) { if (e.getDetail() != null ) { FaultException f = new FaultException(e.getMessage(), e.getDetail(), e); @@ -124,76 +95,11 @@ public class Axis2BindingInvoker implements Invoker, DataExchangeSemantics { } } catch (Throwable e) { msg.setFaultBody(e); - } + } return msg; } - protected Object invokeTarget(Message msg) throws AxisFault { - final OperationClient operationClient = createOperationClient(msg); - - // ensure connections are tracked so that they can be closed by the reference binding - MessageContext requestMC = operationClient.getMessageContext("Out"); - requestMC.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); - requestMC.getOptions().setTimeOutInMilliSeconds(240000L); - - /* - for ( PolicyHandler policyHandler : policyHandlerList ) { - policyHandler.beforeInvoke(msg, requestMC, operationClient); - } - */ - - // set policy specified headers -/* - for (Axis2HeaderPolicy policy : axis2HeaderPolicies){ - Axis2BindingHeaderConfigurator.setHeader(requestMC, msg, policy.getHeaderName()); - } - - if (basicAuthenticationPolicy != null) { - Axis2BindingBasicAuthenticationConfigurator.setOperationOptions(operationClient, msg, basicAuthenticationPolicy); - } - - if (axis2TokenAuthenticationPolicy != null) { - Axis2BindingHeaderConfigurator.setHeader(requestMC, msg, axis2TokenAuthenticationPolicy.getTokenName()); - } -*/ - - // Allow privileged access to read properties. Requires PropertiesPermission read in - // security policy. - try { - AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { - public Object run() throws AxisFault { - operationClient.execute(true); - return null; - } - }); - } catch (PrivilegedActionException e) { - operationClient.complete(requestMC); - throw (AxisFault)e.getException(); - } - - MessageContext responseMC = operationClient.getMessageContext("In"); - - /* - for ( PolicyHandler policyHandler : policyHandlerList ) { - policyHandler.afterInvoke(msg, responseMC, operationClient); - } - */ - - OMElement response = responseMC.getEnvelope().getBody().getFirstElement(); - - // FIXME: [rfeng] We have to pay performance penalty to build the complete OM as the operationClient.complete() will - // release the underlying HTTP connection. - // Force the response to be populated, see https://issues.apache.org/jira/browse/TUSCANY-1541 - if (response != null) { - response.build(); - } - - operationClient.complete(requestMC); - - return response; - } - @SuppressWarnings("deprecation") protected OperationClient createOperationClient(Message msg) throws AxisFault { SOAPEnvelope env = soapFactory.getDefaultEnvelope(); @@ -204,8 +110,7 @@ public class Axis2BindingInvoker implements Invoker, DataExchangeSemantics { if (bc instanceof OMElement) { body.addChild((OMElement)bc); } else { - throw new IllegalArgumentException( - "Can't handle mixed payloads between OMElements and other types."); + throw new IllegalArgumentException( "Can't handle mixed payloads between OMElements and other types."); } } } @@ -213,7 +118,7 @@ public class Axis2BindingInvoker implements Invoker, DataExchangeSemantics { requestMC.setEnvelope(env); // Axis2 operationClients can not be shared so create a new one for each request - final OperationClient operationClient = bindingProvider.getServiceClient().createClient(wsdlOperationName); + final OperationClient operationClient = serviceClient.createClient(wsdlOperationName); operationClient.setOptions(options); Endpoint callbackEndpoint = msg.getFrom().getCallbackEndpoint(); @@ -232,11 +137,6 @@ public class Axis2BindingInvoker implements Invoker, DataExchangeSemantics { sh.addChild(epr); requestMC.setFrom(fromEPR); } - - // Set any message headers required by policy - // Get the header from the tuscany message - // If its not already an OM convert it to OM - // add it to the envelope header // if target endpoint was not specified when this invoker was created, // use dynamically specified target endpoint passed in on this call diff --git a/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/TransportReferenceInterceptor.java b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/TransportReferenceInterceptor.java new file mode 100644 index 0000000000..7daa58bf29 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-ws-runtime-axis2/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/TransportReferenceInterceptor.java @@ -0,0 +1,137 @@ +/* + * 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.binding.ws.axis2.transport; + +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.client.OperationClient; +import org.apache.axis2.client.Options; +import org.apache.axis2.context.MessageContext; +import org.apache.axis2.transport.http.HTTPConstants; +import org.apache.tuscany.sca.interfacedef.util.FaultException; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; + +/** + * Use an Axis2 OperationClient to invoke a remote web service + * + * @version $Rev$ $Date$ + */ +public class TransportReferenceInterceptor implements Interceptor { + + private Invoker next; + + public TransportReferenceInterceptor() { + } + + public Message invoke(Message msg) { + try { + Object resp = null; + + if (msg.getOperation().isNonBlocking()) { + resp = invokeTargetOneWay(msg); + } else { + resp = invokeTarget(msg); + } + + msg.setBody(resp); + } catch (AxisFault e) { + if (e.getDetail() != null ) { + FaultException f = new FaultException(e.getMessage(), e.getDetail(), e); + f.setFaultName(e.getDetail().getQName()); + msg.setFaultBody(f); + } else { + msg.setFaultBody(e); + } + } catch (Throwable e) { + msg.setFaultBody(e); + } + + return msg; + } + + protected Object invokeTarget(Message msg) throws AxisFault { + final OperationClient operationClient = msg.getBindingContext(); + + // ensure connections are tracked so that they can be closed by the reference binding + MessageContext requestMC = operationClient.getMessageContext("Out"); + requestMC.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); + requestMC.getOptions().setTimeOutInMilliSeconds(240000L); + + + // Allow privileged access to read properties. Requires PropertiesPermission read in + // security policy. + try { + AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { + public Object run() throws AxisFault { + operationClient.execute(true); + return null; + } + }); + } catch (PrivilegedActionException e) { + operationClient.complete(requestMC); + throw (AxisFault)e.getException(); + } + + MessageContext responseMC = operationClient.getMessageContext("In"); + + OMElement response = responseMC.getEnvelope().getBody().getFirstElement(); + + // FIXME: [rfeng] We have to pay performance penalty to build the complete OM as the operationClient.complete() will + // release the underlying HTTP connection. + // Force the response to be populated, see https://issues.apache.org/jira/browse/TUSCANY-1541 + if (response != null) { + response.build(); + } + + operationClient.complete(requestMC); + + return response; + } + + protected Object invokeTargetOneWay(Message msg) throws AxisFault { + OperationClient operationClient = msg.getBindingContext(); + + // ensure connections are tracked so that they can be closed by the reference binding + MessageContext requestMC = operationClient.getMessageContext("Out"); + //requestMC.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); + Options opt = requestMC.getOptions(); + opt.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); + opt.setUseSeparateListener(true); + opt.setProperty(HTTPConstants.AUTO_RELEASE_CONNECTION,Boolean.TRUE); + + operationClient.execute(false); + + // REVIEW it seems ok to return null + return null; + } + + public Invoker getNext() { + return next; + } + + public void setNext(Invoker next) { + this.next = next; + } +} |