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: */
019:
020: package org.apache.axis2.handlers.addressing;
021:
022: import org.apache.axiom.om.OMAttribute;
023: import org.apache.axiom.soap.SOAP12Constants;
024: import org.apache.axiom.soap.SOAPHeader;
025: import org.apache.axiom.soap.SOAPHeaderBlock;
026: import org.apache.axis2.AxisFault;
027: import org.apache.axis2.addressing.AddressingConstants;
028: import org.apache.axis2.addressing.AddressingFaultsHelper;
029: import org.apache.axis2.addressing.EndpointReference;
030: import org.apache.axis2.addressing.EndpointReferenceHelper;
031: import org.apache.axis2.addressing.RelatesTo;
032: import org.apache.axis2.client.Options;
033: import org.apache.axis2.context.MessageContext;
034: import org.apache.axis2.handlers.AbstractHandler;
035: import org.apache.axis2.util.LoggingControl;
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038:
039: import javax.xml.namespace.QName;
040: import java.util.ArrayList;
041: import java.util.Iterator;
042:
043: public abstract class AddressingInHandler extends AbstractHandler
044: implements AddressingConstants {
045:
046: protected String addressingNamespace = Final.WSA_NAMESPACE; // defaulting to final version
047: protected String addressingVersion = null;
048: private static final Log log = LogFactory
049: .getLog(AddressingInHandler.class);
050:
051: public InvocationResponse invoke(MessageContext msgContext)
052: throws AxisFault {
053: // if another handler has already processed the addressing headers, do not do anything here.
054: if (msgContext.isPropertyTrue(IS_ADDR_INFO_ALREADY_PROCESSED)) {
055: if (LoggingControl.debugLoggingAllowed
056: && log.isDebugEnabled()) {
057: log
058: .debug("Another handler has processed the addressing headers. Nothing to do here.");
059: }
060: return InvocationResponse.CONTINUE;
061: }
062:
063: // check whether someone has explicitly set which addressing handler should run.
064: String namespace = (String) msgContext
065: .getProperty(WS_ADDRESSING_VERSION);
066: if (namespace == null) {
067: namespace = addressingNamespace;
068: } else if (!namespace.equals(addressingNamespace)) {
069: if (LoggingControl.debugLoggingAllowed
070: && log.isDebugEnabled()) {
071: log
072: .debug("This addressing handler does not match the specified namespace, "
073: + namespace);
074: }
075:
076: return InvocationResponse.CONTINUE;
077: }
078:
079: SOAPHeader header = msgContext.getEnvelope().getHeader();
080:
081: // if there are not headers put a flag to disable addressing temporary
082: if (header == null) {
083: msgContext.setProperty(DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
084: Boolean.TRUE);
085: return InvocationResponse.CONTINUE;
086: }
087:
088: if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled()) {
089: log.debug("Starting " + addressingVersion
090: + " IN handler ...");
091: }
092:
093: ArrayList addressingHeaders;
094: addressingHeaders = header.getHeaderBlocksWithNSURI(namespace);
095: if (addressingHeaders != null && addressingHeaders.size() > 0) {
096: msgContext.setProperty(WS_ADDRESSING_VERSION, namespace);
097: msgContext.setProperty(DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
098: Boolean.FALSE);
099:
100: if (LoggingControl.debugLoggingAllowed
101: && log.isDebugEnabled()) {
102: log
103: .debug(addressingVersion
104: + " Headers present in the SOAP message. Starting to process ...");
105: }
106:
107: extractAddressingInformation(header, msgContext,
108: addressingHeaders, namespace);
109: msgContext.setProperty(IS_ADDR_INFO_ALREADY_PROCESSED,
110: Boolean.TRUE);
111: } else {
112: msgContext.setProperty(DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
113: Boolean.TRUE);
114: if (LoggingControl.debugLoggingAllowed
115: && log.isDebugEnabled()) {
116: log.debug("No Headers present corresponding to "
117: + addressingVersion);
118: }
119: }
120:
121: return InvocationResponse.CONTINUE;
122: }
123:
124: protected Options extractAddressingInformation(SOAPHeader header,
125: MessageContext messageContext, ArrayList addressingHeaders,
126: String namespace) throws AxisFault {
127:
128: Options messageContextOptions = messageContext.getOptions();
129:
130: ArrayList checkedHeaderNames = new ArrayList(7); // Up to 7 header names to be recorded
131: ArrayList duplicateHeaderNames = new ArrayList(1); // Normally will not be used for more than 1 header
132:
133: // Per the SOAP Binding spec "headers with an incorrect cardinality MUST NOT be used" So
134: // these variables are used to keep track of invalid cardinality headers so they are not
135: // deserialised.
136: boolean ignoreTo = false, ignoreFrom = false, ignoreReplyTo = false, ignoreFaultTo = false, ignoreMessageID = false, ignoreAction = false;
137:
138: // First pass just check for duplicates
139: Iterator addressingHeadersIt = addressingHeaders.iterator();
140: while (addressingHeadersIt.hasNext()) {
141: SOAPHeaderBlock soapHeaderBlock = (SOAPHeaderBlock) addressingHeadersIt
142: .next();
143: // TODO - Don't do role processing here!
144: if (!SOAP12Constants.SOAP_ROLE_NONE.equals(soapHeaderBlock
145: .getRole())) {
146: if (WSA_ACTION.equals(soapHeaderBlock.getLocalName())) {
147: ignoreAction = checkDuplicateHeaders(WSA_ACTION,
148: checkedHeaderNames, duplicateHeaderNames);
149: } else if (WSA_TO
150: .equals(soapHeaderBlock.getLocalName())) {
151: ignoreTo = checkDuplicateHeaders(WSA_TO,
152: checkedHeaderNames, duplicateHeaderNames);
153: } else if (WSA_MESSAGE_ID.equals(soapHeaderBlock
154: .getLocalName())) {
155: ignoreMessageID = checkDuplicateHeaders(
156: WSA_MESSAGE_ID, checkedHeaderNames,
157: duplicateHeaderNames);
158: } else if (WSA_REPLY_TO.equals(soapHeaderBlock
159: .getLocalName())) {
160: ignoreReplyTo = checkDuplicateHeaders(WSA_REPLY_TO,
161: checkedHeaderNames, duplicateHeaderNames);
162: } else if (WSA_FAULT_TO.equals(soapHeaderBlock
163: .getLocalName())) {
164: ignoreFaultTo = checkDuplicateHeaders(WSA_FAULT_TO,
165: checkedHeaderNames, duplicateHeaderNames);
166: } else if (WSA_FROM.equals(soapHeaderBlock
167: .getLocalName())) {
168: ignoreFrom = checkDuplicateHeaders(WSA_FROM,
169: checkedHeaderNames, duplicateHeaderNames);
170: }
171: }
172: }
173:
174: // Now extract information
175: Iterator addressingHeadersIt2 = addressingHeaders.iterator();
176: while (addressingHeadersIt2.hasNext()) {
177: SOAPHeaderBlock soapHeaderBlock = (SOAPHeaderBlock) addressingHeadersIt2
178: .next();
179: if (!SOAP12Constants.SOAP_ROLE_NONE.equals(soapHeaderBlock
180: .getRole())) {
181: if (WSA_ACTION.equals(soapHeaderBlock.getLocalName())
182: && !ignoreAction) {
183: extractActionInformation(soapHeaderBlock,
184: messageContext);
185: } else if (WSA_TO
186: .equals(soapHeaderBlock.getLocalName())
187: && !ignoreTo) {
188: extractToEPRInformation(soapHeaderBlock,
189: messageContextOptions, header, namespace);
190: } else if (WSA_MESSAGE_ID.equals(soapHeaderBlock
191: .getLocalName())
192: && !ignoreMessageID) {
193: extractMessageIDInformation(soapHeaderBlock,
194: messageContext);
195: } else if (WSA_REPLY_TO.equals(soapHeaderBlock
196: .getLocalName())
197: && !ignoreReplyTo) {
198: extractReplyToEPRInformation(soapHeaderBlock,
199: namespace, messageContext);
200: } else if (WSA_FAULT_TO.equals(soapHeaderBlock
201: .getLocalName())
202: && !ignoreFaultTo) {
203: extractFaultToEPRInformation(soapHeaderBlock,
204: namespace, messageContext);
205: } else if (WSA_RELATES_TO.equals(soapHeaderBlock
206: .getLocalName())) {
207: extractRelatesToInformation(soapHeaderBlock,
208: messageContextOptions);
209: } else if (WSA_FROM.equals(soapHeaderBlock
210: .getLocalName())
211: && !ignoreFrom) {
212: extractFromEPRInformation(soapHeaderBlock,
213: namespace, messageContext);
214: }
215: }
216: }
217:
218: // Now that all the valid wsa headers have been read, throw an exception if there was an invalid cardinality
219: // This means that if for example there are multiple MessageIDs and a FaultTo, the FaultTo will be respected.
220: if (!duplicateHeaderNames.isEmpty()) {
221: // Simply choose the first problem header we came across as we can only fault for one of them.
222: AddressingFaultsHelper.triggerInvalidCardinalityFault(
223: messageContext, (String) duplicateHeaderNames
224: .get(0));
225: }
226:
227: // check for the presence of madatory addressing headers
228: checkForMandatoryHeaders(checkedHeaderNames, messageContext);
229:
230: // provide default values for headers that have not been found.
231: setDefaults(checkedHeaderNames, messageContext);
232:
233: return messageContextOptions;
234: }
235:
236: protected abstract void checkForMandatoryHeaders(
237: ArrayList alreadyFoundAddrHeader,
238: MessageContext messageContext) throws AxisFault;
239:
240: protected abstract void setDefaults(
241: ArrayList alreadyFoundAddrHeader,
242: MessageContext messageContext) throws AxisFault;
243:
244: private boolean checkDuplicateHeaders(String addressingHeaderName,
245: ArrayList checkedHeaderNames, ArrayList duplicateHeaderNames) {//throws AxisFault {
246: // If the header name has been seen before then we should return true and add it to the list
247: // of duplicate header names. Otherwise it is the first time we've seen the header so add it
248: // to the checked liat and return false.
249: boolean shouldIgnore = checkedHeaderNames
250: .contains(addressingHeaderName);
251: if (shouldIgnore) {
252: duplicateHeaderNames.add(addressingHeaderName);
253: } else {
254: checkedHeaderNames.add(addressingHeaderName);
255: }
256:
257: if (log.isTraceEnabled()) {
258: log.trace("checkDuplicateHeaders: addressingHeaderName="
259: + addressingHeaderName + " isDuplicate="
260: + shouldIgnore);
261: }
262:
263: return shouldIgnore;
264: }
265:
266: protected abstract void extractToEprReferenceParameters(
267: EndpointReference toEPR, SOAPHeader header, String namespace);
268:
269: private void extractRelatesToInformation(
270: SOAPHeaderBlock soapHeaderBlock,
271: Options messageContextOptions) {
272: String address = soapHeaderBlock.getText();
273:
274: // Extract the RelationshipType attribute if it exists
275: OMAttribute relationshipType = soapHeaderBlock
276: .getAttribute(new QName(
277: AddressingConstants.WSA_RELATES_TO_RELATIONSHIP_TYPE));
278:
279: String relationshipTypeString = relationshipType == null ? null
280: : relationshipType.getAttributeValue();
281:
282: if (log.isTraceEnabled()) {
283: log
284: .trace("extractRelatesToInformation: Extracted Relationship. Value="
285: + address
286: + " RelationshipType="
287: + relationshipTypeString);
288: }
289:
290: RelatesTo relatesTo = new RelatesTo(address,
291: relationshipTypeString);
292:
293: ArrayList attributes = extractAttributesFromSOAPHeaderBlock(soapHeaderBlock);
294: relatesTo.setExtensibilityAttributes(attributes);
295:
296: messageContextOptions.addRelatesTo(relatesTo);
297:
298: // Completed processing of this header
299: soapHeaderBlock.setProcessed();
300: }
301:
302: private void extractFaultToEPRInformation(
303: SOAPHeaderBlock soapHeaderBlock,
304: String addressingNamespace, MessageContext messageContext)
305: throws AxisFault {
306: Options messageContextOptions = messageContext.getOptions();
307: EndpointReference epr = messageContextOptions.getFaultTo();
308: if (epr == null) {
309: epr = new EndpointReference("");
310: messageContextOptions.setFaultTo(epr);
311: }
312: extractEPRInformation(soapHeaderBlock, epr,
313: addressingNamespace, messageContext);
314: if (log.isTraceEnabled()) {
315: log
316: .trace("extractFaultToEPRInformation: Extracted FaultTo EPR: "
317: + epr);
318: }
319: soapHeaderBlock.setProcessed();
320: }
321:
322: private void extractReplyToEPRInformation(
323: SOAPHeaderBlock soapHeaderBlock,
324: String addressingNamespace, MessageContext messageContext)
325: throws AxisFault {
326: Options messageContextOptions = messageContext.getOptions();
327: EndpointReference epr = messageContextOptions.getReplyTo();
328: if (epr == null) {
329: epr = new EndpointReference("");
330: messageContextOptions.setReplyTo(epr);
331: }
332: extractEPRInformation(soapHeaderBlock, epr,
333: addressingNamespace, messageContext);
334: if (log.isTraceEnabled()) {
335: log
336: .trace("extractReplyToEPRInformation: Extracted ReplyTo EPR: "
337: + epr);
338: }
339: soapHeaderBlock.setProcessed();
340: }
341:
342: private void extractFromEPRInformation(
343: SOAPHeaderBlock soapHeaderBlock,
344: String addressingNamespace, MessageContext messageContext)
345: throws AxisFault {
346: Options messageContextOptions = messageContext.getOptions();
347: EndpointReference epr = messageContextOptions.getFrom();
348: if (epr == null) {
349: epr = new EndpointReference(""); // I don't know the address now. Let me pass the empty string now and fill this
350: // once I process the Elements under this.
351: messageContextOptions.setFrom(epr);
352: }
353: extractEPRInformation(soapHeaderBlock, epr,
354: addressingNamespace, messageContext);
355: if (log.isTraceEnabled()) {
356: log.trace("extractFromEPRInformation: Extracted From EPR: "
357: + epr);
358: }
359: soapHeaderBlock.setProcessed();
360: }
361:
362: private void extractToEPRInformation(
363: SOAPHeaderBlock soapHeaderBlock,
364: Options messageContextOptions, SOAPHeader header,
365: String namespace) {
366:
367: EndpointReference epr;
368: //here the addressing epr overidde what ever already there in the message context
369: epr = new EndpointReference(soapHeaderBlock.getText());
370: messageContextOptions.setTo(epr);
371:
372: // check for address attributes
373: Iterator addressAttributes = soapHeaderBlock.getAllAttributes();
374: if (addressAttributes != null && addressAttributes.hasNext()) {
375: ArrayList attributes = new ArrayList();
376: while (addressAttributes.hasNext()) {
377: OMAttribute attr = (OMAttribute) addressAttributes
378: .next();
379: attributes.add(attr);
380: }
381: epr.setAddressAttributes(attributes);
382: }
383:
384: // check for reference parameters
385: extractToEprReferenceParameters(epr, header, namespace);
386: soapHeaderBlock.setProcessed();
387:
388: if (log.isTraceEnabled()) {
389: log.trace("extractToEPRInformation: Extracted To EPR: "
390: + epr);
391: }
392: }
393:
394: //We assume that any action that already exists in the message context must be the
395: //soapaction. We compare that action to the WS-Addressing action, and if they are
396: //different we throw a fault.
397: private void extractActionInformation(
398: SOAPHeaderBlock soapHeaderBlock,
399: MessageContext messageContext) throws AxisFault {
400: Options messageContextOptions = messageContext.getOptions();
401: String soapAction = messageContextOptions.getAction();
402: String wsaAction = soapHeaderBlock.getText();
403:
404: if (log.isTraceEnabled()) {
405: log.trace("extractActionInformation: soapAction='"
406: + soapAction + "' wsa:Action='" + wsaAction + "'");
407: }
408:
409: // Need to validate that the content of the wsa:Action header is not null or whitespace
410: if ((wsaAction == null) || "".equals(wsaAction.trim())) {
411: AddressingFaultsHelper.triggerActionNotSupportedFault(
412: messageContext, wsaAction);
413: }
414:
415: // The isServerSide check is because the underlying Options object is
416: // shared between request and response MessageContexts for Sync
417: // invocations. If the soapAction is set outbound and a wsa:Action is
418: // received on the response they will differ (because there is no
419: // SOAPAction header on an HTTP response). In this case we should not
420: // check that soapAction==wsa:Action
421: if (soapAction != null && !"".equals(soapAction)
422: && messageContext.isServerSide()) {
423: if (!soapAction.equals(wsaAction)) {
424: AddressingFaultsHelper
425: .triggerActionMismatchFault(messageContext);
426: }
427: } else {
428: messageContextOptions.setAction(wsaAction);
429: }
430:
431: ArrayList attributes = extractAttributesFromSOAPHeaderBlock(soapHeaderBlock);
432: if (attributes != null) {
433: messageContext.setProperty(
434: AddressingConstants.ACTION_ATTRIBUTES, attributes);
435: }
436:
437: soapHeaderBlock.setProcessed();
438: }
439:
440: private void extractMessageIDInformation(
441: SOAPHeaderBlock soapHeaderBlock,
442: MessageContext messageContext) throws AxisFault {
443: messageContext.getOptions().setMessageId(
444: soapHeaderBlock.getText());
445:
446: ArrayList attributes = extractAttributesFromSOAPHeaderBlock(soapHeaderBlock);
447: if (attributes != null) {
448: messageContext.setProperty(
449: AddressingConstants.MESSAGEID_ATTRIBUTES,
450: attributes);
451: }
452:
453: soapHeaderBlock.setProcessed();
454: }
455:
456: /**
457: * Given the soap header block, this should extract the information within EPR.
458: *
459: * @param headerBlock a SOAP header which is of type EndpointReference
460: * @param epr the EndpointReference to fill in with the extracted data
461: * @param addressingNamespace the WSA namespace URI
462: * @param messageContext the active MessageContext
463: * @throws AxisFault if there is a problem
464: */
465: private void extractEPRInformation(SOAPHeaderBlock headerBlock,
466: EndpointReference epr, String addressingNamespace,
467: MessageContext messageContext) throws AxisFault {
468: try {
469: EndpointReferenceHelper.fromOM(epr, headerBlock,
470: addressingNamespace);
471: } catch (AxisFault af) {
472: if (log.isTraceEnabled()) {
473: log
474: .trace(
475: "extractEPRInformation: Exception occurred deserialising an EndpointReference.",
476: af);
477: }
478: AddressingFaultsHelper.triggerMissingAddressInEPRFault(
479: messageContext, headerBlock.getLocalName());
480: }
481: }
482:
483: private ArrayList extractAttributesFromSOAPHeaderBlock(
484: SOAPHeaderBlock soapHeaderBlock) {
485: Iterator actionAttributes = soapHeaderBlock.getAllAttributes();
486: if (actionAttributes != null && actionAttributes.hasNext()) {
487: ArrayList attributes = new ArrayList();
488: while (actionAttributes.hasNext()) {
489: OMAttribute attr = (OMAttribute) actionAttributes
490: .next();
491: attributes.add(attr);
492: }
493: return attributes;
494: }
495: return null;
496: }
497: }
|