001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.ws.addressing;
019:
020: import java.lang.reflect.Method;
021: import java.util.Map;
022: import java.util.UUID;
023: import java.util.concurrent.Executor;
024: import java.util.logging.Level;
025: import java.util.logging.Logger;
026:
027: import javax.jws.WebMethod;
028: import javax.jws.WebService;
029: import javax.xml.bind.JAXBContext;
030: import javax.xml.bind.JAXBElement;
031: import javax.xml.bind.JAXBException;
032: import javax.xml.namespace.QName;
033: import javax.xml.ws.RequestWrapper;
034: import javax.xml.ws.ResponseWrapper;
035: import javax.xml.ws.WebFault;
036:
037: import org.apache.cxf.Bus;
038: import org.apache.cxf.binding.soap.model.SoapOperationInfo;
039: import org.apache.cxf.common.logging.LogUtils;
040: import org.apache.cxf.common.util.PackageUtils;
041: import org.apache.cxf.common.util.TwoStageMap;
042: import org.apache.cxf.endpoint.ConduitSelector;
043: import org.apache.cxf.endpoint.Endpoint;
044: import org.apache.cxf.endpoint.NullConduitSelector;
045: import org.apache.cxf.endpoint.PreexistingConduitSelector;
046: import org.apache.cxf.interceptor.Fault;
047: import org.apache.cxf.interceptor.InterceptorChain;
048: import org.apache.cxf.interceptor.OutgoingChainInterceptor;
049: import org.apache.cxf.message.Exchange;
050: import org.apache.cxf.message.Message;
051: import org.apache.cxf.service.model.BindingOperationInfo;
052: import org.apache.cxf.service.model.MessageInfo;
053: import org.apache.cxf.service.model.OperationInfo;
054: import org.apache.cxf.transport.Conduit;
055: import org.apache.cxf.transport.Destination;
056: import org.apache.cxf.workqueue.OneShotAsyncExecutor;
057: import org.apache.cxf.workqueue.SynchronousExecutor;
058: import org.apache.cxf.workqueue.WorkQueueManager;
059: import org.apache.cxf.wsdl.EndpointReferenceUtils;
060:
061: import static org.apache.cxf.message.Message.ASYNC_POST_RESPONSE_DISPATCH;
062: import static org.apache.cxf.message.Message.REQUESTOR_ROLE;
063:
064: import static org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES;
065: import static org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES_INBOUND;
066: import static org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES_OUTBOUND;
067: import static org.apache.cxf.ws.addressing.JAXWSAConstants.SERVER_ADDRESSING_PROPERTIES_INBOUND;
068: import static org.apache.cxf.ws.addressing.JAXWSAConstants.SERVER_ADDRESSING_PROPERTIES_OUTBOUND;
069:
070: /**
071: * Holder for utility methods relating to contexts.
072: */
073: public final class ContextUtils {
074:
075: public static final ObjectFactory WSA_OBJECT_FACTORY = new ObjectFactory();
076:
077: private static final String WS_ADDRESSING_PACKAGE = PackageUtils
078: .getPackageName(EndpointReferenceType.class);
079: private static final EndpointReferenceType NONE_ENDPOINT_REFERENCE = EndpointReferenceUtils
080: .getEndpointReference(Names.WSA_NONE_ADDRESS);
081: private static final String HTTP_URI_SCHEME = "http:";
082: private static final String URI_AUTHORITY_PREFIX = "//";
083: private static final Map<BindingOperationInfo, String> ACTION_MAP = new TwoStageMap<BindingOperationInfo, String>();
084:
085: private static final Logger LOG = LogUtils
086: .getL7dLogger(ContextUtils.class);
087:
088: /**
089: * Used to fabricate a Uniform Resource Name from a UUID string
090: */
091: private static final String URN_UUID = "urn:uuid:";
092:
093: private static JAXBContext jaxbContext;
094:
095: /**
096: * Used by MAPAggregator to cache bad MAP fault name
097: */
098: private static final String MAP_FAULT_NAME_PROPERTY = "org.apache.cxf.ws.addressing.map.fault.name";
099:
100: /**
101: * Used by MAPAggregator to cache bad MAP fault reason
102: */
103: private static final String MAP_FAULT_REASON_PROPERTY = "org.apache.cxf.ws.addressing.map.fault.reason";
104:
105: /**
106: * Indicates a partial response has already been sent
107: */
108: private static final String PARTIAL_REPONSE_SENT_PROPERTY = "org.apache.cxf.ws.addressing.partial.response.sent";
109:
110: /**
111: * Prevents instantiation.
112: */
113: private ContextUtils() {
114: }
115:
116: /**
117: * Determine if message is outbound.
118: *
119: * @param message the current Message
120: * @return true iff the message direction is outbound
121: */
122: public static boolean isOutbound(Message message) {
123: Exchange exchange = message.getExchange();
124: return message != null
125: && exchange != null
126: && (message == exchange.getOutMessage() || message == exchange
127: .getOutFaultMessage());
128: }
129:
130: /**
131: * Determine if message is fault.
132: *
133: * @param message the current Message
134: * @return true iff the message is a fault
135: */
136: public static boolean isFault(Message message) {
137: return message != null
138: && message.getExchange() != null
139: && (message == message.getExchange()
140: .getInFaultMessage() || message == message
141: .getExchange().getOutFaultMessage());
142: }
143:
144: /**
145: * Determine if current messaging role is that of requestor.
146: *
147: * @param message the current Message
148: * @return true iff the current messaging role is that of requestor
149: */
150: public static boolean isRequestor(Message message) {
151: Boolean requestor = (Boolean) message.get(REQUESTOR_ROLE);
152: return requestor != null && requestor.booleanValue();
153: }
154:
155: /**
156: * Get appropriate property name for message addressing properties.
157: *
158: * @param isProviderContext true if the binding provider request context
159: * available to the client application as opposed to the message context
160: * visible to handlers
161: * @param isRequestor true iff the current messaging role is that of
162: * requestor
163: * @param isOutbound true iff the message is outbound
164: * @return the property name to use when caching the MAPs in the context
165: */
166: public static String getMAPProperty(boolean isRequestor,
167: boolean isProviderContext, boolean isOutbound) {
168: return isRequestor ? isProviderContext ? CLIENT_ADDRESSING_PROPERTIES
169: : isOutbound ? CLIENT_ADDRESSING_PROPERTIES_OUTBOUND
170: : CLIENT_ADDRESSING_PROPERTIES_INBOUND
171: : isOutbound ? SERVER_ADDRESSING_PROPERTIES_OUTBOUND
172: : SERVER_ADDRESSING_PROPERTIES_INBOUND;
173: }
174:
175: /**
176: * Store MAPs in the message.
177: *
178: * @param message the current message
179: * @param isOutbound true iff the message is outbound
180: */
181: public static void storeMAPs(AddressingProperties maps,
182: Message message, boolean isOutbound) {
183: storeMAPs(maps, message, isOutbound, isRequestor(message),
184: false);
185: }
186:
187: /**
188: * Store MAPs in the message.
189: *
190: * @param maps the MAPs to store
191: * @param message the current message
192: * @param isOutbound true iff the message is outbound
193: * @param isRequestor true iff the current messaging role is that of
194: * requestor
195: * @param handler true if HANDLER scope, APPLICATION scope otherwise
196: */
197: public static void storeMAPs(AddressingProperties maps,
198: Message message, boolean isOutbound, boolean isRequestor) {
199: storeMAPs(maps, message, isOutbound, isRequestor, false);
200: }
201:
202: /**
203: * Store MAPs in the message.
204: *
205: * @param maps the MAPs to store
206: * @param message the current message
207: * @param isOutbound true iff the message is outbound
208: * @param isRequestor true iff the current messaging role is that of
209: * requestor
210: * @param handler true if HANDLER scope, APPLICATION scope otherwise
211: * @param isProviderContext true if the binding provider request context
212: */
213: public static void storeMAPs(AddressingProperties maps,
214: Message message, boolean isOutbound, boolean isRequestor,
215: boolean isProviderContext) {
216: if (maps != null) {
217: String mapProperty = getMAPProperty(isRequestor,
218: isProviderContext, isOutbound);
219: LOG.log(Level.INFO,
220: "associating MAPs with context property {0}",
221: mapProperty);
222: message.put(mapProperty, maps);
223: }
224: }
225:
226: /**
227: * @param message the current message
228: * @param isProviderContext true if the binding provider request context
229: * available to the client application as opposed to the message context
230: * visible to handlers
231: * @param isOutbound true iff the message is outbound
232: * @return the current addressing properties
233: */
234: public static AddressingPropertiesImpl retrieveMAPs(
235: Message message, boolean isProviderContext,
236: boolean isOutbound) {
237: return retrieveMAPs(message, isProviderContext, isOutbound,
238: true);
239: }
240:
241: /**
242: * @param message the current message
243: * @param isProviderContext true if the binding provider request context
244: * available to the client application as opposed to the message context
245: * visible to handlers
246: * @param isOutbound true iff the message is outbound
247: * @param warnIfMissing log a warning message if properties cannot be retrieved
248: * @return the current addressing properties
249: */
250: public static AddressingPropertiesImpl retrieveMAPs(
251: Message message, boolean isProviderContext,
252: boolean isOutbound, boolean warnIfMissing) {
253: boolean isRequestor = ContextUtils.isRequestor(message);
254: String mapProperty = ContextUtils.getMAPProperty(
255: isProviderContext, isRequestor, isOutbound);
256: LOG.log(Level.INFO,
257: "retrieving MAPs from context property {0}",
258: mapProperty);
259: AddressingPropertiesImpl maps = (AddressingPropertiesImpl) message
260: .get(mapProperty);
261: if (maps != null) {
262: LOG.log(Level.INFO, "current MAPs {0}", maps);
263: } else if (!isProviderContext) {
264: LogUtils.log(LOG, warnIfMissing ? Level.WARNING
265: : Level.INFO, "MAPS_RETRIEVAL_FAILURE_MSG");
266: }
267: return maps;
268: }
269:
270: /**
271: * Helper method to get an attributed URI.
272: *
273: * @param uri the URI
274: * @return an AttributedURIType encapsulating the URI
275: */
276: public static AttributedURIType getAttributedURI(String uri) {
277: AttributedURIType attributedURI = WSA_OBJECT_FACTORY
278: .createAttributedURIType();
279: attributedURI.setValue(uri);
280: return attributedURI;
281: }
282:
283: /**
284: * Helper method to get a RealtesTo instance.
285: *
286: * @param uri the related URI
287: * @return a RelatesToType encapsulating the URI
288: */
289: public static RelatesToType getRelatesTo(String uri) {
290: RelatesToType relatesTo = WSA_OBJECT_FACTORY
291: .createRelatesToType();
292: relatesTo.setValue(uri);
293: return relatesTo;
294: }
295:
296: /**
297: * Helper method to determine if an EPR address is generic (either null,
298: * none or anonymous).
299: *
300: * @param ref the EPR under test
301: * @return true iff the address is generic
302: */
303: public static boolean isGenericAddress(EndpointReferenceType ref) {
304: return ref == null
305: || ref.getAddress() == null
306: || Names.WSA_ANONYMOUS_ADDRESS.equals(ref.getAddress()
307: .getValue())
308: || Names.WSA_NONE_ADDRESS.equals(ref.getAddress()
309: .getValue());
310: }
311:
312: /**
313: * Helper method to determine if an MAPs Action is empty (a null action
314: * is considered empty, whereas a zero length action suppresses
315: * the propogation of the Action property).
316: *
317: * @param ref the MAPs Action under test
318: * @return true iff the Action is empty
319: */
320: public static boolean hasEmptyAction(AddressingProperties maps) {
321: boolean empty = maps.getAction() == null;
322: if (maps.getAction() != null
323: && maps.getAction().getValue().length() == 0) {
324: maps.setAction(null);
325: empty = false;
326: }
327: return empty;
328: }
329:
330: /**
331: * Rebase response on replyTo
332: *
333: * @param reference the replyTo reference
334: * @param inMAPs the inbound MAPs
335: * @param inMessage the current message
336: */
337: public static void rebaseResponse(EndpointReferenceType reference,
338: AddressingProperties inMAPs, final Message inMessage) {
339: String namespaceURI = inMAPs.getNamespaceURI();
340: if (!retrievePartialResponseSent(inMessage)) {
341: storePartialResponseSent(inMessage);
342: Exchange exchange = inMessage.getExchange();
343: Message fullResponse = exchange.getOutMessage();
344: Message partialResponse = createMessage(exchange);
345: ensurePartialResponseMAPs(partialResponse, namespaceURI);
346:
347: // ensure the inbound MAPs are available in the partial response
348: // message (used to determine relatesTo etc.)
349: propogateReceivedMAPs(inMAPs, partialResponse);
350: partialResponse.put(Message.PARTIAL_RESPONSE_MESSAGE,
351: Boolean.TRUE);
352: Destination target = inMessage.getDestination();
353: if (target == null) {
354: return;
355: }
356:
357: try {
358: exchange.setOutMessage(partialResponse);
359: Conduit backChannel = target.getBackChannel(inMessage,
360: partialResponse, reference);
361:
362: if (backChannel != null) {
363: // set up interceptor chains and send message
364: InterceptorChain chain = fullResponse != null ? fullResponse
365: .getInterceptorChain()
366: : OutgoingChainInterceptor
367: .getOutInterceptorChain(exchange);
368: partialResponse.setInterceptorChain(chain);
369: exchange.put(ConduitSelector.class,
370: new PreexistingConduitSelector(backChannel,
371: exchange.get(Endpoint.class)));
372:
373: if (!partialResponse.getInterceptorChain()
374: .doIntercept(partialResponse)
375: && partialResponse
376: .getContent(Exception.class) != null) {
377: if (partialResponse.getContent(Exception.class) instanceof Fault) {
378: throw (Fault) partialResponse
379: .getContent(Exception.class);
380: } else {
381: throw new Fault(partialResponse
382: .getContent(Exception.class));
383: }
384: }
385:
386: partialResponse.getInterceptorChain().reset();
387: exchange.put(ConduitSelector.class,
388: new NullConduitSelector());
389: if (fullResponse != null) {
390: exchange.setOutMessage(fullResponse);
391: } else {
392: fullResponse = createMessage(exchange);
393: exchange.setOutMessage(fullResponse);
394: }
395:
396: if (retrieveAsyncPostResponseDispatch(inMessage)) {
397: // async service invocation required *after* a response
398: // has been sent (i.e. to a oneway, or a partial response
399: // to a decoupled twoway)
400:
401: // pause dispatch on current thread ...
402: inMessage.getInterceptorChain().pause();
403:
404: // ... and resume on executor thread
405: getExecutor(inMessage).execute(new Runnable() {
406: public void run() {
407: inMessage.getInterceptorChain()
408: .resume();
409: }
410: });
411: }
412: }
413: } catch (Exception e) {
414: LOG.log(Level.WARNING,
415: "SERVER_TRANSPORT_REBASE_FAILURE_MSG", e);
416: }
417: }
418: }
419:
420: /**
421: * Propogate inbound MAPs onto full reponse & fault messages.
422: *
423: * @param inMAPs the inbound MAPs
424: * @param exchange the current Exchange
425: */
426: public static void propogateReceivedMAPs(
427: AddressingProperties inMAPs, Exchange exchange) {
428: if (exchange.getOutMessage() == null) {
429: exchange.setOutMessage(createMessage(exchange));
430: }
431: propogateReceivedMAPs(inMAPs, exchange.getOutMessage());
432: if (exchange.getOutFaultMessage() == null) {
433: exchange.setOutFaultMessage(createMessage(exchange));
434: }
435: propogateReceivedMAPs(inMAPs, exchange.getOutFaultMessage());
436: }
437:
438: /**
439: * Propogate inbound MAPs onto reponse message if applicable
440: * (not applicable for oneways).
441: *
442: * @param inMAPs the inbound MAPs
443: * @param responseMessage
444: */
445: private static void propogateReceivedMAPs(
446: AddressingProperties inMAPs, Message responseMessage) {
447: if (responseMessage != null) {
448: storeMAPs(inMAPs, responseMessage, false, false, false);
449: }
450: }
451:
452: /**
453: * Construct and store MAPs for partial response.
454: *
455: * @param partialResponse the partial response message
456: * @param namespaceURI the current namespace URI
457: */
458: private static void ensurePartialResponseMAPs(
459: Message partialResponse, String namespaceURI) {
460: // ensure there is a MAPs instance available for the outbound
461: // partial response that contains appropriate To and ReplyTo
462: // properties (i.e. anonymous & none respectively)
463: AddressingPropertiesImpl maps = new AddressingPropertiesImpl();
464: maps.setTo(EndpointReferenceUtils
465: .getAnonymousEndpointReference());
466: maps.setReplyTo(WSA_OBJECT_FACTORY
467: .createEndpointReferenceType());
468: maps.getReplyTo().setAddress(
469: getAttributedURI(Names.WSA_NONE_ADDRESS));
470: maps.setAction(getAttributedURI(""));
471: maps.exposeAs(namespaceURI);
472: storeMAPs(maps, partialResponse, true, true, false);
473: }
474:
475: /**
476: * Get the Executor for this invocation.
477: * @param endpoint
478: * @return
479: */
480: private static Executor getExecutor(final Message message) {
481: Endpoint endpoint = message.getExchange().get(Endpoint.class);
482: Executor executor = endpoint.getService().getExecutor();
483:
484: if (executor == null || SynchronousExecutor.isA(executor)) {
485: // need true asynchrony
486: Bus bus = message.getExchange().get(Bus.class);
487: if (bus != null) {
488: WorkQueueManager workQueueManager = bus
489: .getExtension(WorkQueueManager.class);
490: Executor autoWorkQueue = workQueueManager
491: .getAutomaticWorkQueue();
492: executor = autoWorkQueue != null ? autoWorkQueue
493: : OneShotAsyncExecutor.getInstance();
494: } else {
495: executor = OneShotAsyncExecutor.getInstance();
496: }
497: }
498: message.getExchange().put(Executor.class, executor);
499: return executor;
500: }
501:
502: /**
503: * Store bad MAP fault name in the message.
504: *
505: * @param faultName the fault name to store
506: * @param message the current message
507: */
508: public static void storeMAPFaultName(String faultName,
509: Message message) {
510: message.put(MAP_FAULT_NAME_PROPERTY, faultName);
511: }
512:
513: /**
514: * Retrieve MAP fault name from the message.
515: *
516: * @param message the current message
517: * @returned the retrieved fault name
518: */
519: public static String retrieveMAPFaultName(Message message) {
520: return (String) message.get(MAP_FAULT_NAME_PROPERTY);
521: }
522:
523: /**
524: * Store MAP fault reason in the message.
525: *
526: * @param reason the fault reason to store
527: * @param message the current message
528: */
529: public static void storeMAPFaultReason(String reason,
530: Message message) {
531: message.put(MAP_FAULT_REASON_PROPERTY, reason);
532: }
533:
534: /**
535: * Retrieve MAP fault reason from the message.
536: *
537: * @param message the current message
538: * @returned the retrieved fault reason
539: */
540: public static String retrieveMAPFaultReason(Message message) {
541: return (String) message.get(MAP_FAULT_REASON_PROPERTY);
542: }
543:
544: /**
545: * Store an indication that a partial response has been sent.
546: * Relavant if *both* the replyTo & faultTo are decoupled,
547: * and a fault occurs, then we would already have sent the
548: * partial response (pre-dispatch) for the replyTo, so
549: * no need to send again.
550: *
551: * @param message the current message
552: */
553: public static void storePartialResponseSent(Message message) {
554: message.put(PARTIAL_REPONSE_SENT_PROPERTY, Boolean.TRUE);
555: }
556:
557: /**
558: * Retrieve indication that a partial response has been sent.
559: *
560: * @param message the current message
561: * @returned the retrieved indication that a partial response
562: * has been sent
563: */
564: public static boolean retrievePartialResponseSent(Message message) {
565: Boolean ret = (Boolean) message
566: .get(PARTIAL_REPONSE_SENT_PROPERTY);
567: return ret != null && ret.booleanValue();
568: }
569:
570: /**
571: * Retrieve indication that an async post-response service invocation
572: * is required.
573: *
574: * @param message the current message
575: * @returned the retrieved indication that an async post-response service
576: * invocation is required.
577: */
578: public static boolean retrieveAsyncPostResponseDispatch(
579: Message message) {
580: Boolean ret = (Boolean) message
581: .get(ASYNC_POST_RESPONSE_DISPATCH);
582: return ret != null && ret.booleanValue();
583: }
584:
585: /**
586: * Retrieve a JAXBContext for marshalling and unmarshalling JAXB generated
587: * types.
588: *
589: * @return a JAXBContext
590: */
591: public static JAXBContext getJAXBContext() throws JAXBException {
592: synchronized (ContextUtils.class) {
593: if (jaxbContext == null) {
594: jaxbContext = JAXBContext
595: .newInstance(WS_ADDRESSING_PACKAGE);
596: }
597: }
598: return jaxbContext;
599: }
600:
601: /**
602: * Set the encapsulated JAXBContext (used by unit tests).
603: *
604: * @param ctx JAXBContext
605: */
606: public static void setJAXBContext(JAXBContext ctx)
607: throws JAXBException {
608: synchronized (ContextUtils.class) {
609: jaxbContext = ctx;
610: }
611: }
612:
613: /**
614: * @return a generated UUID
615: */
616: public static String generateUUID() {
617: return URN_UUID + UUID.randomUUID();
618: }
619:
620: /**
621: * Retreive Conduit from Exchange if not already available
622: *
623: * @param conduit the current value for the Conduit
624: * @param message the current message
625: * @return the Conduit if available
626: */
627: public static Conduit getConduit(Conduit conduit, Message message) {
628: if (conduit == null) {
629: Exchange exchange = message.getExchange();
630: conduit = exchange != null ? exchange.getConduit(message)
631: : null;
632: }
633: return conduit;
634: }
635:
636: /**
637: * Construct the Action URI.
638: *
639: * @param message the current message
640: * @return the Action URI
641: */
642: public static AttributedURIType getAction(Message message) {
643: String action = null;
644: LOG.fine("Determining action");
645: Exception fault = message.getContent(Exception.class);
646:
647: // REVISIT: add support for @{Fault}Action annotation (generated
648: // from the wsaw:Action WSDL element). For the moment we just
649: // pick up the wsaw:Action attribute by walking the WSDL model
650: // directly
651: action = getActionFromServiceModel(message, fault);
652:
653: if (action == null) {
654: Method method = getMethod(message);
655: LOG.fine("method: " + method + ", fault: " + fault);
656: if (method != null) {
657: action = getActionFromAnnotations(message, method,
658: fault);
659: }
660: }
661: LOG.fine("action: " + action);
662: return action != null ? getAttributedURI(action) : null;
663: }
664:
665: /**
666: * Get action from service model.
667: *
668: * @param message the current message
669: * @param fault the fault if one is set
670: */
671: private static String getActionFromServiceModel(Message message,
672: Exception fault) {
673: String action = null;
674: if (fault == null) {
675: BindingOperationInfo bindingOpInfo = message.getExchange()
676: .get(BindingOperationInfo.class);
677: if (bindingOpInfo != null) {
678: SoapOperationInfo soi = bindingOpInfo
679: .getExtensor(SoapOperationInfo.class);
680: if (null != soi) {
681: action = soi.getAction();
682: }
683:
684: if (action == null || "".equals(action)) {
685: String cachedAction = ACTION_MAP.get(bindingOpInfo);
686: if (cachedAction == null) {
687: MessageInfo msgInfo = ContextUtils
688: .isRequestor(message) ? bindingOpInfo
689: .getInput().getMessageInfo()
690: : bindingOpInfo.getOutput()
691: .getMessageInfo();
692: action = getActionFromMessageAttributes(
693: bindingOpInfo, msgInfo);
694: } else {
695: action = cachedAction;
696: }
697: }
698: }
699: } else {
700: // FaultAction attribute is not defined in
701: // http://www.w3.org/2005/02/addressing/wsdl schema
702: }
703: LOG.fine("action determined from service model: " + action);
704: return action;
705: }
706:
707: /**
708: * Get action from attributes on MessageInfo
709: *
710: * @param bindingOpInfo the current BindingOperationInfo
711: * @param msgInfo the current MessageInfo
712: * @return the action if set
713: */
714: private static String getActionFromMessageAttributes(
715: BindingOperationInfo bindingOpInfo, MessageInfo msgInfo) {
716: String action = null;
717: if (msgInfo != null && msgInfo.getExtensionAttributes() != null) {
718: QName attr = (QName) msgInfo.getExtensionAttributes().get(
719: Names.WSAW_ACTION_QNAME);
720: if (attr != null) {
721: action = getURI(attr.getLocalPart());
722: ACTION_MAP.put(bindingOpInfo, action);
723: }
724: }
725: return action;
726: }
727:
728: /**
729: * Get action from annotations.
730: *
731: * @param message the current message
732: * @param method the invoked on method
733: * @param fault the fault if one is set
734: */
735: private static String getActionFromAnnotations(Message message,
736: Method method, Exception fault) {
737: String action = null;
738: if (fault != null) {
739: WebFault webFault = fault.getClass().getAnnotation(
740: WebFault.class);
741: if (webFault != null) {
742: action = getAction(webFault.targetNamespace(), method,
743: webFault.name(), true);
744: }
745: } else {
746: String namespace = getWrapperNamespace(message, method);
747: if (namespace != null) {
748: action = getAction(namespace, method,
749: getWrapperLocalName(message, method), false);
750: } else {
751: WebService wsAnnotation = method.getDeclaringClass()
752: .getAnnotation(WebService.class);
753: WebMethod wmAnnotation = method
754: .getAnnotation(WebMethod.class);
755: action = wsAnnotation != null && wmAnnotation != null ? getAction(
756: wsAnnotation.targetNamespace(), method,
757: wmAnnotation.operationName(), false)
758: : null;
759: }
760: }
761: LOG.fine("action determined from annotations: " + action);
762: return action;
763: }
764:
765: /**
766: * Get the target namespace from the {Request|Response}Wrapper annotation
767: *
768: * @param message the current message
769: * @param method the target method
770: * @return the annotated namespace
771: */
772: private static String getWrapperNamespace(Message message,
773: Method method) {
774: String namespace = null;
775: if (ContextUtils.isRequestor(message)) {
776: RequestWrapper requestWrapper = method
777: .getAnnotation(RequestWrapper.class);
778: if (requestWrapper != null) {
779: namespace = requestWrapper.targetNamespace();
780: }
781: } else {
782: ResponseWrapper responseWrapper = method
783: .getAnnotation(ResponseWrapper.class);
784: if (responseWrapper != null) {
785: namespace = responseWrapper.targetNamespace();
786: }
787: }
788: return namespace;
789: }
790:
791: /**
792: * Get the target local name from the {Request|Response}Wrapper annotation
793: *
794: * @param message the current message
795: * @param method the target method
796: * @return the annotated local name
797: */
798: private static String getWrapperLocalName(Message message,
799: Method method) {
800: String localName = null;
801: if (ContextUtils.isRequestor(message)) {
802: RequestWrapper requestWrapper = method
803: .getAnnotation(RequestWrapper.class);
804: if (requestWrapper != null) {
805: localName = requestWrapper.localName();
806: }
807: } else {
808: ResponseWrapper responseWrapper = method
809: .getAnnotation(ResponseWrapper.class);
810: if (responseWrapper != null) {
811: localName = responseWrapper.localName();
812: }
813: }
814: return localName;
815: }
816:
817: /**
818: * Construct the Action string.
819: *
820: * @param targetNamespace the target namespace
821: * @param method the method
822: * @param localName the local name
823: * @param isFault true if a fault
824: * @return action string
825: */
826: private static String getAction(String targetNamespace,
827: Method method, String localName, boolean isFault) {
828: String action = null;
829: action = targetNamespace;
830: action += Names.WSA_ACTION_DELIMITER;
831: action += method.getDeclaringClass().getSimpleName();
832: if (isFault) {
833: action += method.getName();
834: action += Names.WSA_FAULT_DELIMITER;
835: }
836: action += Names.WSA_ACTION_DELIMITER;
837: action += localName;
838: return action;
839: }
840:
841: /**
842: * Get the current Method.
843: *
844: * @param message the current message
845: * @return the Method from the BindingOperationInfo
846: */
847: private static Method getMethod(Message message) {
848: Method method = null;
849: BindingOperationInfo bindingOpInfo = message.getExchange().get(
850: BindingOperationInfo.class);
851: if (bindingOpInfo != null) {
852: OperationInfo opInfo = bindingOpInfo.getOperationInfo();
853: if (opInfo != null) {
854: method = (Method) opInfo.getProperty(Method.class
855: .getName());
856: }
857: }
858: return method;
859: }
860:
861: /**
862: * @param s a string that may be a URI without a scheme identifier
863: * @return a properly formed URI
864: */
865: private static String getURI(String s) {
866: String uri = null;
867: if (s.startsWith(HTTP_URI_SCHEME)) {
868: uri = s;
869: } else if (s.startsWith(URI_AUTHORITY_PREFIX)) {
870: uri = HTTP_URI_SCHEME + s;
871: } else {
872: uri = HTTP_URI_SCHEME + URI_AUTHORITY_PREFIX + s;
873: }
874: return uri;
875: }
876:
877: public static EndpointReferenceType getNoneEndpointReference() {
878: return NONE_ENDPOINT_REFERENCE;
879: }
880:
881: public static void applyReferenceParam(EndpointReferenceType toEpr,
882: JAXBElement<String> el) {
883: if (null == toEpr.getReferenceParameters()) {
884: toEpr.setReferenceParameters(WSA_OBJECT_FACTORY
885: .createReferenceParametersType());
886: }
887: toEpr.getReferenceParameters().getAny().add(el);
888: }
889:
890: /**
891: * Create a Binding specific Message.
892: *
893: * @param message the current message
894: * @return the Method from the BindingOperationInfo
895: */
896: private static Message createMessage(Exchange exchange) {
897: Endpoint ep = exchange.get(Endpoint.class);
898: Message msg = null;
899: if (ep != null) {
900: msg = ep.getBinding().createMessage();
901: }
902: return msg;
903: }
904:
905: }
|