001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: /*
038: * ProtocolMessageSender.java
039: *
040: * @author Mike Grogan
041: * Created on January 30, 2006, 12:12 PM
042: *
043: */
044:
045: package com.sun.xml.ws.rm.jaxws.runtime.client;
046:
047: import com.sun.xml.ws.api.SOAPVersion;
048: import com.sun.xml.ws.api.WSBinding;
049: import com.sun.xml.ws.api.message.HeaderList;
050: import com.sun.xml.ws.api.message.Message;
051: import com.sun.xml.ws.api.message.Messages;
052: import com.sun.xml.ws.api.message.Packet;
053: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
054: import com.sun.xml.ws.api.pipe.Tube;
055: import com.sun.xml.ws.rm.*;
056: import com.sun.xml.ws.rm.jaxws.runtime.InboundMessageProcessor;
057: import com.sun.xml.ws.rm.jaxws.runtime.OutboundSequence;
058: import com.sun.xml.ws.rm.jaxws.runtime.SequenceConfig;
059: import com.sun.xml.ws.rm.protocol.AbstractAckRequested;
060: import com.sun.xml.ws.rm.protocol.AbstractCreateSequence;
061: import com.sun.xml.ws.rm.protocol.AbstractCreateSequenceResponse;
062: import com.sun.xml.ws.rm.protocol.AbstractTerminateSequence;
063: import com.sun.xml.ws.rm.v200502.AckRequestedElement;
064: import com.sun.xml.ws.rm.v200502.SequenceElement;
065: import com.sun.xml.ws.rm.v200702.CloseSequenceElement;
066: import com.sun.xml.ws.rm.v200702.CloseSequenceResponseElement;
067:
068: import javax.xml.bind.JAXBException;
069: import javax.xml.bind.Marshaller;
070: import javax.xml.bind.Unmarshaller;
071: import java.net.URI;
072:
073: /**
074: * Helper class used to send protocol message addressed to the endpoint.
075: * The messages belong to the following types:
076: * <ul>
077: * <li>CreateSequence. A message with a CreateSequence element in its body is sent. The
078: * response message contains a CreateSequenceResponse element in its body</li>
079: * <li>Last. A message with empty body, and a Sequence header with Last child
080: * is sent. The headers on the body are processed.</li>
081: * <li>AckRequensted. A message with empty body, and a Sequence header with Last child
082: * is sent. The headers on the body are processed.</li>
083: * <li>TerminateSequence A message with a TerminateSequence element in its body is sent.</li>
084: * </ul>
085: *
086: */
087: public class ProtocolMessageSender {
088:
089: /**
090: * Helper to process InboundMessages.
091: */
092: private InboundMessageProcessor processor;
093:
094: /**
095: * The marshaller to write the messages
096: */
097: private Marshaller marshaller;
098: /**
099: * The unmarshaller to read the messages
100: */
101: private Unmarshaller unmarshaller;
102:
103: private RMConstants constants;
104:
105: /**
106: * Properties like the BindingProvider to associate with the
107: * request and response context
108: * contentNegotiation etc can be obtained from
109: * the packet
110: */
111: private Packet packet;
112:
113: /*
114: * WSDLPort for use by addressing module when assigning headers.
115: */
116: private WSDLPort port;
117:
118: /*
119: * WSBinding for use by addressing module when assigning headers.
120: */
121: private WSBinding binding;
122:
123: private SequenceConfig config;
124:
125: private final ProtocolMessageHelper helper;
126:
127: /**
128: * Public ctor. Initialize the fields
129: */
130: public ProtocolMessageSender(InboundMessageProcessor processor,
131: SequenceConfig config, Marshaller marshaller,
132: Unmarshaller unmarshaller, WSDLPort port,
133: WSBinding binding, Tube nextTube, Packet packet) {
134:
135: this .processor = processor;
136: this .port = port;
137: this .binding = binding;
138: this .marshaller = marshaller;
139: this .unmarshaller = unmarshaller;
140: this .constants = RMConstants.getRMConstants(binding
141: .getAddressingVersion());
142: this .packet = packet;
143: this .config = config;
144: this .helper = new ProtocolMessageHelper(nextTube);
145:
146: }
147:
148: public AbstractCreateSequenceResponse sendCreateSequence(
149: AbstractCreateSequence cs, URI destination, URI acksTo,
150: SOAPVersion version) throws RMException {
151:
152: //Used from com.sun.xml.ws.jaxws.runtime.client.ClientOutboundSequence.connect, where
153: //CreateSequence object is constructed and resulting CreateSequenceResponse object is
154: //processed.
155: AbstractCreateSequenceResponse csrElem = null;
156:
157: //1. Initialize message adding CreateSequence to body
158: if (cs != null) {
159: Message request = null;
160: if (config.getRMVersion() == RMVersion.WSRM10) {
161: request = Messages
162: .create(
163: config.getRMVersion().getJAXBContext(),
164: ((com.sun.xml.ws.rm.v200502.CreateSequenceElement) cs),
165: version);
166: } else {
167: request = Messages
168: .create(
169: config.getRMVersion().getJAXBContext(),
170: ((com.sun.xml.ws.rm.v200702.CreateSequenceElement) cs),
171: version);
172: }
173:
174: //Addressing Headers are added by configuring the following property
175: //on the packet
176:
177: Packet requestPacket = new Packet(request);
178: requestPacket.proxy = packet.proxy;
179: requestPacket.contentNegotiation = packet.contentNegotiation;
180: requestPacket.setEndPointAddressString(destination
181: .toString());
182:
183: addAddressingHeaders(requestPacket, config.getRMVersion()
184: .getCreateSequenceAction(), destination, acksTo,
185: false);
186:
187: String messageId = null;/*= ADDRESSING_FIXME - initialize with mesageID
188: assigned by addAddressingHeaders for use in
189: correlating non-anonymous acksTo response*/
190:
191: Packet responsePacket = helper.process(requestPacket);
192:
193: if (acksTo.equals(constants.getAnonymousURI())) {
194:
195: Message response = responsePacket.getMessage();
196: if (response.isFault()) {
197: throw new CreateSequenceException(
198: "CreateSequence was refused by the RMDestination \n ",
199: response);
200: }
201:
202: //unmarshall CreateSequenceResponse object from body of response.
203: //need the null check because this might be a non-anonymous ackto and
204: //CSR will be processed on another connection.
205: if (response != null) {
206: csrElem = unmarshallCreateSequenceResponse(response);
207: }
208: } else {
209:
210: csrElem = ProtocolMessageReceiver
211: .getCreateSequenceResponse(messageId);
212: }
213: }
214:
215: return csrElem;
216: }
217:
218: public void sendTerminateSequence(AbstractTerminateSequence ts,
219: OutboundSequence seq, SOAPVersion version)
220: throws RMException {
221:
222: //Used from com.sun.xml.ws.jaxws.runtime.client.ClientOutboundSequence.disconnect, where the
223: //TerminateSequence message is initialzied.
224:
225: Message request = Messages.create(config.getRMVersion()
226: .getJAXBContext(), ts, version);
227:
228: //piggyback an acknowledgement if one is pending
229: seq.processAcknowledgement(new com.sun.xml.ws.rm.Message(
230: request, config.rmVersion), marshaller);
231:
232: Packet requestPacket = new Packet(request);
233: requestPacket.proxy = packet.proxy;
234: requestPacket.contentNegotiation = packet.contentNegotiation;
235: addAddressingHeaders(requestPacket, config.getRMVersion()
236: .getTerminateSequenceAction(), seq.getDestination(),
237: seq.getAcksTo(),/*true*/false);
238: requestPacket.setEndPointAddressString(seq.getDestination()
239: .toString());
240: Packet responsePacket = helper.process(requestPacket);
241: Message response = responsePacket.getMessage();
242: if (response != null && response.isFault()) {
243: throw new TerminateSequenceException(
244: "There was an error trying to terminate the sequence ",
245: response);
246: }
247:
248: //What to do with response?
249: //TODO
250: //It may have a TerminateSequence for reverse sequence on it as well as
251: //ack headers
252: //Process these.
253:
254: }
255:
256: /**
257: * Send Message with empty body and a single SequenceElement (with Last child) down the pipe. Process the response,
258: * which may contain a SequenceAcknowledgementElement.
259: *
260: * @param seq Outbound sequence to which SequenceHeaderElement will belong.
261: *
262: */
263: public void sendLast(OutboundSequence seq, SOAPVersion version)
264: throws RMException {
265:
266: Message request = createEmptyMessage(version);
267: SequenceElement el = createLastHeader(seq);
268: //request.getHeaders().add(Headers.create(version,marshaller,el));
269: request.getHeaders().add(createHeader(el));
270:
271: seq.setLast();
272:
273: Packet requestPacket = new Packet(request);
274: requestPacket.proxy = packet.proxy;
275: //requestPacket.proxy = new ProxyWrapper(packet.proxy);
276: requestPacket.setEndPointAddressString(seq.getDestination()
277: .toString());
278: requestPacket.contentNegotiation = packet.contentNegotiation;
279: addAddressingHeaders(requestPacket, config.getRMVersion()
280: .getLastAction(), seq.getDestination(),
281: seq.getAcksTo(), /*true*/false);
282:
283: Packet responsePacket = helper.process(requestPacket);
284: Message response = responsePacket.getMessage();
285:
286: com.sun.xml.ws.rm.Message msg = new com.sun.xml.ws.rm.Message(
287: response, config.rmVersion);
288: if (response != null && response.isFault()) {
289: throw new RMException(response);
290: }
291:
292: processor.processMessage(msg, marshaller, unmarshaller);
293:
294: }
295:
296: /**
297: * Send Message with empty body and a AckRequestedElement (with Last child) down the pipe. Process the response,
298: * which may contain a SequenceAcknowledgementElement.
299: *
300: * @param seq Outbound sequence to which SequenceHeaderElement will belong.
301: *
302: */
303: public void sendAckRequested(OutboundSequence seq,
304: SOAPVersion version) throws RMException {
305:
306: try {
307: Message request = createEmptyMessage(version);
308: AbstractAckRequested el = createAckRequestedElement(seq);
309: //request.getHeaders().add(Headers.create(version,marshaller,el));
310: request.getHeaders().add(createHeader(el));
311:
312: Packet requestPacket = new Packet(request);
313: requestPacket.proxy = packet.proxy;
314: requestPacket.contentNegotiation = packet.contentNegotiation;
315:
316: addAddressingHeaders(requestPacket, config.getRMVersion()
317: .getAckRequestedAction(), seq.getDestination(), seq
318: .getAcksTo(), /*true*/false);
319:
320: requestPacket.setEndPointAddressString(seq.getDestination()
321: .toString());
322:
323: Packet responsePacket = helper.process(requestPacket);
324: Message response = responsePacket.getMessage();
325: if (response != null && response.isFault()) {
326: //reset alarm
327: ((ClientOutboundSequence) seq).resetLastActivityTime();
328: throw new RMException(response);
329: }
330:
331: com.sun.xml.ws.rm.Message msg = new com.sun.xml.ws.rm.Message(
332: response, config.rmVersion);
333: processor.processMessage(msg, marshaller, unmarshaller);
334: } finally {
335: //Make sure that alarm is reset.
336: ((ClientOutboundSequence) seq).resetLastActivityTime();
337: }
338:
339: }
340:
341: /**
342: * Initialize an AddressingProperties object using the arguments. Put the AddressingProperties
343: * object in the RequestContext obtained from getMessageProperties.
344: */
345: private Packet addAddressingHeaders(Packet requestPacket,
346: String action, URI destination, URI acksTo, boolean oneWay)
347: throws RMException {
348:
349: /*ADDRESSING FIX_ME
350:
351: Current API does not allow assignment of non-anon reply to, if we
352: need to support non-anon acksTo.
353: */
354: Message message = requestPacket.getMessage();
355: HeaderList list = message.getHeaders();
356: if (oneWay) {
357: message.assertOneWay(true);
358: } else {
359: message.assertOneWay(false);
360: }
361: //list.fillRequestAddressingHeaders(port, binding, requestPacket, action);
362: requestPacket.setEndPointAddressString(destination.toString());
363: list.fillRequestAddressingHeaders(requestPacket, constants
364: .getAddressingVersion(), binding.getSOAPVersion(),
365: oneWay, action);
366:
367: return requestPacket;
368:
369: }
370:
371: /**
372: * Create an empty message using correct SOAPVersion
373: */
374: private Message createEmptyMessage(SOAPVersion version) {
375: return Messages.createEmpty(version);
376: }
377:
378: private AbstractCreateSequenceResponse unmarshallCreateSequenceResponse(
379: Message response) throws RMException {
380: try {
381: return response.readPayloadAsJAXB(unmarshaller);
382: } catch (JAXBException e) {
383: throw new RMException(e);
384: }
385: }
386:
387: /**
388: * Return a <code>SequenceElement.LastMessage</code>
389: */
390: private SequenceElement createLastHeader(OutboundSequence seq) {
391: SequenceElement sequenceElement = new SequenceElement();
392: sequenceElement.setId(seq.getId());
393: sequenceElement.setNumber(seq.getNextIndex());
394: sequenceElement
395: .setLastMessage(new SequenceElement.LastMessage());
396: return sequenceElement;
397: }
398:
399: /**
400: * Return a <code>AckReqesutedElement</code> whose Sequence ID matches the specified
401: * <code>OutboundSequence</code> and whose MessageNumber is the
402: * highest <MessageNumber> sent within a Sequence
403: * sequence.
404: */
405: private AbstractAckRequested createAckRequestedElement(
406: OutboundSequence seq) {
407: AbstractAckRequested ackRequestedElement = null;
408: if (config.getRMVersion() == RMVersion.WSRM10) {
409: ackRequestedElement = new AckRequestedElement();
410: ackRequestedElement.setId(seq.getId());
411: } else {
412: ackRequestedElement = new com.sun.xml.ws.rm.v200702.AckRequestedElement();
413: ackRequestedElement.setId(seq.getId());
414: }
415:
416: return ackRequestedElement;
417: }
418:
419: public RMConstants getConstants() {
420: return constants;
421: }
422:
423: private com.sun.xml.ws.api.message.Header createHeader(Object obj) {
424: return com.sun.xml.ws.api.message.Headers.create(config
425: .getRMVersion().getJAXBRIContextHeaders(), obj);
426: }
427:
428: public void sendCloseSequence(OutboundSequence seq,
429: SOAPVersion version) throws RMException {
430:
431: Message request = null;
432:
433: CloseSequenceElement cs = new CloseSequenceElement();
434: com.sun.xml.ws.rm.v200702.Identifier idClose = new com.sun.xml.ws.rm.v200702.Identifier();
435: idClose.setValue(seq.getId());
436:
437: cs.setIdentifier(idClose);
438: cs.setLastMsgNumber(seq.getNextIndex() - 1);
439:
440: request = Messages.create(config.getRMVersion()
441: .getJAXBContext(), cs, version);
442: Packet requestPacket = new Packet(request);
443: requestPacket.proxy = packet.proxy;
444: requestPacket.contentNegotiation = packet.contentNegotiation;
445: requestPacket.setEndPointAddressString(seq.getDestination()
446: .toString());
447:
448: addAddressingHeaders(requestPacket, RMVersion.WSRM11
449: .getCloseSequenceAction(), seq.getDestination(), null,
450: false);
451:
452: String messageId = null;/*= ADDRESSING_FIXME - initialize with mesageID
453: assigned by addAddressingHeaders for use in
454: correlating non-anonymous acksTo response*/
455:
456: seq.setClosed();
457:
458: Packet responsePacket = helper.process(requestPacket);
459:
460: Message response = responsePacket.getMessage();
461: if (response.isFault()) {
462: throw new CloseSequenceException(
463: "CloseSequence was refused by the RMDestination \n ",
464: response);
465: }
466:
467: //unmarshall CloseSequenceResponse object from body of response.
468:
469: CloseSequenceResponseElement csrElem = unmarshallCloseSequenceResponse(response);
470:
471: }
472:
473: private CloseSequenceResponseElement unmarshallCloseSequenceResponse(
474: Message response) throws RMException {
475: try {
476: return response.readPayloadAsJAXB(unmarshaller);
477: } catch (JAXBException e) {
478: throw new RMException(e);
479: }
480: }
481:
482: }
|