The core asynchronous invoker in Apache Tuscany for ws-binding is the Axis2OneWayBindingInvoker.java file. The message on the wire is done in the following way:
27
28
29
30
31 public interface Message {
32
33
34
35
36
37 T getBody();
38
39
40
41
42
43 void setBody(T body);
44
45
46
47
48
49 String getConversationID();
50
51
52
53
54
55 void setConversationID(String conversationId);
56
57
58
59
60
61 EndpointReference getFrom();
62
63
64
65
66
67 void setFrom(EndpointReference from);
68
69
70
71
72
73 EndpointReference getTo();
74
75
76
77
78
79 void setTo(EndpointReference to);
80
81
82
83
84
85 Object getMessageID();
86
87
88
89
90
91 void setMessageID(Object messageId);
92
93
94
95
96
97
98 Object getCorrelationID();
99
100
101
102
103
104 void setCorrelationID(Object correlationId);
105
106
107
108
109
110
111 boolean isFault();
112
113
114
115
116
117
118 void setFaultBody(T fault);
119
120
121
122
123
124
125 ConversationSequence getConversationSequence();
126
127
128
129
130
131
132 void setConversationSequence(ConversationSequence sequence);
133
134
135
136
137
138
139 Operation getOperation();
140
141
142
143
144
145
146 void setOperation(Operation op);
147
148
149
150
151
152
153 CallableReference getCallableReference();
154
155
156
157
158
159
160 void setCallableReference(CallableReference callableReference);
161
162 }
From the code we see that a Message has a :
- a message identificator
- a correlation id
- a conversation id
- a body
- an operation
- two endpoint reference (from, to)
I assume to have a factory, called MessageFactory in order to create messages.
Now we'll look how a message is sent on the wire in the asynchronous case file Axis2OneWayBindingInvoker.java :
protected Object invokeTarget(Message msg) throws InvocationTargetException {
47 try {
We'll speak about AxisOperationClient later:
1) Create an OperationClient with the incoming Message
48 OperationClient operationClient = createOperationClient(msg);
49
50 // ensure connections are tracked so that they can be closed by the reference binding
51 MessageContext requestMC = operationClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
52
53
requestMC.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE);
It's asynchronous so it should not block, so execute(false) means : DON'T BLOCK!
54 operationClient.execute(false);
55
56 // REVIEW it seems ok to return null
57 return null;
58
59 } catch (AxisFault e) {
60 throw new InvocationTargetException(e);
61 }
What does operation client ?
You can use Operation Client if you want more control during the invocation. Typically you need to work with the Message Context. Axis2 creates an instance of Message Context for each and every SOAP message handled inside the engine. Message Context encapsulates a SOAP message and it has most of the information required to process the message. Axis2 engine is a stateless piece of code which executes according to the information found inside the Message Context.
Operation Client enables user to directly access or pass-in a Message Context so that user has the ability to set numerous parameters to be used during an invocation. User can even set a complete SOAP envelope to the message context, created by any means he likes. (Service Client API has means to set the content of body and it has addHeader()
) method to add headers to the SOAP messages. So Service Client user can also customize the SOAP message, to some extent, just like the Operation Client user.)
You need to know a bit about the concept of MEP (Message Exchange Pattern) to use Operation Client API.
Message Exchange Pattern (MEP)
During a request-response invocation, we first send a SOAP message to the Web service and it then returns back another SOAP message to us. From the Web service's point of view, it receives one incoming message (IN message) and sends out one message (OUT message). This is a pattern and we name this message exchange as IN-OUT MEP. Similarly, there can be another Web service which simply accepts messages from client. For example, you can register with a new alert system by sending a subscription request message (assume, you will become a member as soon as you send this request and server doesn't send a confirmation message). In this case you are working with an IN-only MEP.
In simple terms, MEP is a template that establishes a pattern for the exchange of messages between two communicating parties.
Then in superclass there's the method for creating an operation client:
protected OperationClient createOperationClient(Message msg) throws AxisFault {
Create a default SOAP envelope:
109 SOAPEnvelope env = soapFactory.getDefaultEnvelope();
Fill the envelope with items using AXIOM:
110 Object[] args = (Object[])msg.getBody();
111 if (args != null && args.length > 0) {
112 SOAPBody body = env.getBody();
113 for (Object bc : args) {
114 if (bc instanceof OMElement) {
115 body.addChild((OMElement)bc);
116 } else {
117 throw new IllegalArgumentException(
118 "Can't handle mixed payloads betweem OMElements and other types.");
119 }
120 }
121 }
After ending the creation of a SOAP Envelope, create a MessageContext
122 MessageContext requestMC = new MessageContext();
123 requestMC.setEnvelope(env);
124
125 // Axis2 operationClients can not be shared so create a new one for each request
126 OperationClient operationClient = serviceClient.createClient(wsdlOperationName);
127
128 String conversationId = msg.getConversationID();
129 if (conversationId != null && conversationId.length() != 0) {
130 EndpointReference fromEPR = new EndpointReference(AddressingConstants.Final.WSA_ANONYMOUS_URL);
131 fromEPR.addReferenceParameter(CONVERSATION_ID_REFPARM_QN, conversationId);
132 options.setFrom(fromEPR);
133 requestMC.setFrom(fromEPR); //who knows why two ways ?
134
135 //For now do this the brute force method. Need to figure out how to do axis addressing .. configure mar in flow.
136 SOAPEnvelope sev = requestMC.getEnvelope();
137 SOAPHeader sh = sev.getHeader();
138 OMElement el =
139 fromEPR.toOM(AddressingConstants.Final.WSA_NAMESPACE,
140 AddressingConstants.WSA_FROM,
141 AddressingConstants.WSA_DEFAULT_PREFIX);
142 sh.addChild(el);
143 }
144
145 operationClient.setOptions(options);
146 // if target endpoint was not specified when this invoker was created,
147 // use dynamically specified target endpoint passed in on this call
148 if (options.getTo() == null) {
149 org.apache.tuscany.sca.runtime.EndpointReference ep = msg.getTo();
150 if (ep != null) {
151 requestMC.setTo(new EndpointReference(ep.getURI()));
152 } else {
153 throw new RuntimeException("Unable to determine destination endpoint");
154 }
155 }
156 //FIXME: need to consolidate the following code with similar code above for
157 // conversations, so that conversations and callbacks work when used together
158 if (options.getFrom() != null) {
159 requestMC.setFrom(options.getFrom());
160 //FIXME: is there any way to use the Axis2 addressing support for this?
161 SOAPEnvelope sev = requestMC.getEnvelope();
162 SOAPHeader sh = sev.getHeader();
163 OMElement el =
164 options.getFrom().toOM(AddressingConstants.Final.WSA_NAMESPACE,
165 AddressingConstants.WSA_FROM,
166 AddressingConstants.WSA_DEFAULT_PREFIX);
167 sh.addChild(el);
168 } else if (msg.getFrom() != null) {
169 EndpointReference fromEpr = new EndpointReference(msg.getFrom().getURI());
170 requestMC.setFrom(fromEpr);
171 SOAPEnvelope sev = requestMC.getEnvelope();
172 SOAPHeader sh = sev.getHeader();
173 OMElement el = fromEpr.toOM(AddressingConstants.Final.WSA_NAMESPACE,
174 AddressingConstants.WSA_FROM,
175 AddressingConstants.WSA_DEFAULT_PREFIX);
176 sh.addChild(el);
177 } else {
178 // the from field remains blank
179 }
180 operationClient.addMessageContext(requestMC);
181
182 return operationClient;
183 }
Axis2OneWayBindingInvoker is called by Axis2Client. For each operation It creates an invoker.
protected Invoker createInvoker(Operation operation) {
139 Options options = new Options();
140 EndpointReference epTo = getPortLocationEPR(wsBinding);
141 if (epTo != null) {
142 options.setTo(epTo);
143 }
144 if (callbackBinding != null) {
145 options.setFrom(getPortLocationEPR(callbackBinding));
146 }
147 options.setProperty(HTTPConstants.CHUNKED, Boolean.FALSE);
148
149 String operationName = operation.getName();
150
151 String soapAction = getSOAPAction(operationName);
152 if (soapAction != null && soapAction.length() > 1) {
153 options.setAction(soapAction);
154 }
155
156 options.setTimeOutInMilliSeconds(30 * 1000); // 30 seconds
157
158 SOAPFactory soapFactory = OMAbstractFactory.getSOAP11Factory();
159 QName wsdlOperationQName = new QName(operationName);
160
161 // Axis2BindingInvoker invoker;
162 if (operation.isNonBlocking()) {
163 invoker = new Axis2OneWayBindingInvoker(serviceClient, wsdlOperationQName, options, soapFactory);
164 } else {
165 invoker = new Axis2BindingInvoker(serviceClient, wsdlOperationQName, options, soapFactory);
166 }
167 return invoker;
168 }