001: /*
002: * BEGIN_HEADER - DO NOT EDIT
003: *
004: * The contents of this file are subject to the terms
005: * of the Common Development and Distribution License
006: * (the "License"). You may not use this file except
007: * in compliance with the License.
008: *
009: * You can obtain a copy of the license at
010: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
011: * See the License for the specific language governing
012: * permissions and limitations under the License.
013: *
014: * When distributing Covered Code, include this CDDL
015: * HEADER in each file and include the License file at
016: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
017: * If applicable add the following below this CDDL HEADER,
018: * with the fields enclosed by brackets "[]" replaced with
019: * your own identifying information: Portions Copyright
020: * [year] [name of copyright owner]
021: */
022:
023: /*
024: * @(#)MessageNormalizerImpl.java
025: * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
026: *
027: * END_HEADER - DO NOT EDIT
028: */
029: package com.sun.jbi.common.soap;
030:
031: import org.w3c.dom.Node;
032: import org.w3c.dom.NodeList;
033:
034: import java.util.Iterator;
035: import java.util.logging.Level;
036: import java.util.logging.Logger;
037: import java.util.StringTokenizer;
038:
039: import java.net.HttpURLConnection;
040:
041: import javax.jbi.JBIException;
042: import javax.jbi.messaging.NormalizedMessage;
043: import javax.jbi.messaging.MessagingException;
044:
045: import javax.xml.soap.Detail;
046: import javax.xml.soap.SOAPBody;
047: import javax.xml.soap.SOAPEnvelope;
048: import javax.xml.soap.SOAPException;
049: import javax.xml.soap.SOAPHeader;
050: import javax.xml.soap.SOAPMessage;
051: import javax.xml.soap.SOAPPart;
052: import javax.xml.soap.SOAPFault;
053: import javax.xml.soap.AttachmentPart;
054: import javax.xml.soap.SOAPElement;
055: import javax.xml.soap.Name;
056:
057: import javax.activation.DataHandler;
058:
059: import org.w3c.dom.Document;
060: import org.w3c.dom.DOMException;
061: import org.w3c.dom.NodeList;
062: import org.w3c.dom.Attr;
063: import org.w3c.dom.Element;
064: import javax.xml.transform.dom.DOMSource;
065: import javax.xml.transform.stream.StreamSource;
066: import javax.xml.transform.TransformerFactory;
067: import javax.xml.transform.Transformer;
068: import javax.xml.transform.stream.StreamResult;
069: import javax.xml.transform.Source;
070:
071: import javax.xml.parsers.DocumentBuilder;
072: import javax.xml.parsers.DocumentBuilderFactory;
073: import javax.xml.parsers.FactoryConfigurationError;
074: import javax.xml.parsers.ParserConfigurationException;
075:
076: /**
077: * This implementation converts a SOAP request message to a JBI specific format which can
078: * be understood by other JBI components.
079: *
080: * @author Sun Microsystems, Inc.
081: */
082: public class MessageNormalizerImpl implements MessageNormalizer {
083: /**
084: * Internal handle to the logger instance
085: */
086: private Logger mLogger;
087:
088: /**
089: * Internal handle to String Translator instance.
090: */
091: private StringTranslator mStringTranslator;
092:
093: /**
094: * Creates a new instance of MessageNormalizerImpl.
095: *
096: */
097: public MessageNormalizerImpl() {
098: mLogger = Logger.getLogger(this .getClass().getPackage()
099: .getName());
100: mStringTranslator = new StringTranslator(this .getClass()
101: .getPackage().getName(), this .getClass()
102: .getClassLoader());
103: }
104:
105: /**
106: * Converts a SOAP Message to a NormalizedMessage format.
107: *
108: * @param soapWrapper request message.
109: * @param normalizedMessage jbi specific format.
110: * @param operation operation requested.
111: *
112: * @throws JBIException if the message cannot be normalized.
113: */
114: public void normalizeMessage(SOAPWrapper soapWrapper,
115: NormalizedMessage normalizedMessage, Operation operation)
116: throws JBIException {
117: if (soapWrapper.getStatus() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
118: normalizeFaultMessage(soapWrapper, normalizedMessage);
119: } else {
120: normalizeResponseMessage(soapWrapper, normalizedMessage,
121: operation);
122: }
123: }
124:
125: /**
126: * Converts a SOAP Fault Message to a NormalizedMessage format.
127: *
128: * @param soapWrapper request message.
129: * @param normalizedMessage jbi specific format.
130: *
131: * @throws JBIException if the message cannot be normalized.
132: */
133: public void normalizeFaultMessage(SOAPWrapper soapWrapper,
134: NormalizedMessage normalizedMessage) throws JBIException {
135:
136: try {
137: SOAPMessage soapMessage = soapWrapper.getMessage();
138:
139: if (soapMessage != null) {
140: SOAPPart soapPart = soapMessage.getSOAPPart();
141: SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
142: SOAPBody soapBody = soapEnvelope.getBody();
143: if (soapBody.hasFault()) {
144: // The Message contains a fault detail element.
145: // Propogate the details in the message content.
146: // ,fault string and fault actor in the message properties.
147:
148: mLogger.info(mStringTranslator
149: .getString("SBC_FAULT_ELEMENT_FOUND"));
150:
151: SOAPFault soapFault = soapBody.getFault();
152: Detail soapDetail = soapFault.getDetail();
153: if (soapDetail != null) {
154: normalizedMessage.setContent(new DOMSource(
155: getChildElement(soapDetail)));
156: // Populate the SOAP Header into the message context
157: SOAPHeader soapHeader = soapEnvelope
158: .getHeader();
159:
160: if (soapHeader != null) {
161: normalizedMessage.setProperty(
162: SOAPConstants.HEADER_PROPERTY_NAME,
163: soapHeader);
164: }
165: normalizedMessage
166: .setProperty(
167: SOAPConstants.FAULT_STRING_PROPERTY_NAME,
168: soapFault.getFaultString());
169: normalizedMessage.setProperty(
170: SOAPConstants.FAULT_CODE_PROPERTY_NAME,
171: extractFaultCode(soapFault
172: .getFaultCode()));
173: } else {
174: // The Message does not contain fault detail. Propogate details
175: // as a JBIException.
176: throw new JBIException(soapFault
177: .getFaultString());
178: }
179:
180: } else {
181: // this should not happen.
182: mLogger.severe(mStringTranslator
183: .getString("SBC_ALGORITHM_ERROR"));
184: }
185: }
186: } catch (SOAPException soapException) {
187: mLogger.severe(mStringTranslator
188: .getString("SBC_NORMALIZE_FAULT_MESSAGE_FAILURE"));
189:
190: mLogger.severe(mStringTranslator
191: .getString("SBC_ERROR_DETAILS"));
192: JBIException jbiException = new JBIException(
193: mStringTranslator
194: .getString("SBC_NORMALIZE_FAULT_MESSAGE_FAILURE"));
195: jbiException.initCause(soapException);
196: throw jbiException;
197: }
198: }
199:
200: /**
201: * Converts a SOAP Response Message to a JBI NormalizedMessage.
202: *
203: * @param soapWrapper request message.
204: * @param normalizedMessage jbi normalized message.
205: * @param operation operation details.
206: *
207: * @throws JBIException if the message cannot be normalized.
208: */
209: public void normalizeResponseMessage(SOAPWrapper soapWrapper,
210: NormalizedMessage normalizedMessage, Operation operation)
211: throws JBIException {
212: mLogger.info(mStringTranslator
213: .getString("SBC_NORMALIZE_SOAP_MESSAGE"));
214: try {
215: SOAPMessage soapMessage = soapWrapper.getMessage();
216:
217: if (soapMessage != null) {
218: SOAPPart soapPart = soapMessage.getSOAPPart();
219: SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
220: SOAPBody soapBody = soapEnvelope.getBody();
221:
222: // Check whether the soap body has all namespace prefixes resolved.
223: // If not resolve them
224: // Populate the SOAP body into the message content.
225: org.w3c.dom.Node bodyContents = getBodyContentsAsNode(soapBody);
226: DOMSource ds = new DOMSource(bodyContents);
227: //dump(ds);
228: normalizedMessage.setContent(ds);
229: /* extractPayload(soapBody, operation,
230: isFault(soapWrapper.getStatus()))));*/
231:
232: // Attach attachments to the normalizedMessage
233: normalizeAttachments(soapMessage, normalizedMessage);
234:
235: // Populate the SOAP Header into the message context
236: SOAPHeader soapHeader = soapEnvelope.getHeader();
237:
238: if (soapHeader != null) {
239: //normalizedMessage.setProperty(
240: // SOAPConstants.HEADER_PROPERTY_NAME, soapHeader);
241: }
242: }
243:
244: Iterator messageProperties = soapWrapper.getProperties();
245:
246: for (; messageProperties.hasNext();) {
247: String propertyName = (String) messageProperties.next();
248: normalizedMessage.setProperty(propertyName, soapWrapper
249: .getValue(propertyName));
250: }
251: } catch (RuntimeException runtimeException) {
252: // This should not happen.
253: mLogger
254: .severe(mStringTranslator
255: .getString("SBC_NORMALIZE_SOAP_MESSAGE_FAILURE_RT_EXP"));
256:
257: JBIException jbiException = new JBIException(
258: mStringTranslator
259: .getString("SBC_NORMALIZE_SOAP_MESSAGE_FAILURE"));
260: jbiException.initCause(runtimeException);
261: throw jbiException;
262: } catch (SOAPException soapException) {
263: mLogger.severe(mStringTranslator
264: .getString("SBC_NORMALIZE_SOAP_MESSAGE_FAILURE"));
265: mLogger.severe(mStringTranslator.getString(
266: "SBC_ERROR_DETAILS", soapException.toString()));
267:
268: JBIException jbiException = new JBIException(
269: mStringTranslator
270: .getString("SBC_NORMALIZE_SOAP_MESSAGE_FAILURE"));
271: jbiException.initCause(soapException);
272: throw jbiException;
273: } catch (Exception ex) {
274: mLogger.severe("Some Exception while dumping Source.");
275: ex.printStackTrace();
276: }
277:
278: mLogger.info(mStringTranslator
279: .getString("SBC_SUCCESS_NORMALISE_SUCCESS"));
280: }
281:
282: private org.w3c.dom.Node getBodyContentsAsNode(SOAPBody body) {
283: org.w3c.dom.Node dNode = null;
284: try {
285: DocumentBuilderFactory factory = DocumentBuilderFactory
286: .newInstance();
287: DocumentBuilder builder = factory.newDocumentBuilder();
288: Document mDoc = builder.newDocument();
289:
290: Iterator iter2 = body.getChildElements();
291: //This code will not work if there are multiple child elements under
292: // soap:Body
293: while (iter2.hasNext()) {
294: javax.xml.soap.Node n = (javax.xml.soap.Node) iter2
295: .next();
296: if (n instanceof SOAPElement) {
297: dNode = createDOMNodeFromSOAPNode(n, mDoc);
298: //dump(new DOMSource(dNode));
299: break;
300: }
301: }
302: } catch (ParserConfigurationException pce) {
303: pce.printStackTrace();
304: return null;
305: } catch (Exception e) {
306: e.printStackTrace();
307: return null;
308: }
309:
310: return dNode;
311:
312: }
313:
314: /**
315: * Creates a DOM Node from a SOAP Node, using the given DOM Document object
316: * to own the DOM Node.
317: */
318: private org.w3c.dom.Node createDOMNodeFromSOAPNode(
319: javax.xml.soap.Node soapNode, Document document)
320: throws ParserConfigurationException {
321: org.w3c.dom.Node result = null;
322:
323: // First figure out what type the soapNode is. Unlike DOM nodes, there
324: // is no "nodeType" property, so we have to use reflection.
325: if (soapNode instanceof SOAPElement) {
326: SOAPElement soapElement = (SOAPElement) soapNode;
327: Name name = soapElement.getElementName();
328:
329: // Create the DOM Element.
330: if ((name.getURI().length() != 0)
331: && (name.getQualifiedName().length() != 0))
332: result = document.createElementNS(name.getURI(), name
333: .getQualifiedName());
334: else if (name.getLocalName() != null)
335: result = document.createElement(name.getLocalName());
336: else {
337: //What to do??
338: }
339:
340: // Iterate through the attributes of the SOAP node and add each one
341: // to the DOM Node.
342: for (Iterator iter = soapElement.getAllAttributes(); iter
343: .hasNext();) {
344: Name attrName = (Name) iter.next();
345: String attrValue = soapElement
346: .getAttributeValue(attrName);
347:
348: // The createAttributeNS method fails if you give it a null URI.
349: Attr attribute = null;
350: if (attrName.getURI() == null)
351: attribute = document.createAttribute(attrName
352: .getQualifiedName());
353: else
354: attribute = document.createAttributeNS(attrName
355: .getURI(), attrName.getQualifiedName());
356:
357: attribute.setValue(attrValue);
358:
359: ((Element) result).setAttributeNodeNS(attribute);
360: }
361:
362: // Iterate through the child elements of the SOAP node, recursing
363: // on this method to add the child SOAP node to the newly created
364: // DOM node.
365: for (Iterator iter = soapElement.getChildElements(); iter
366: .hasNext();) {
367: javax.xml.soap.Node childSOAPNode = (javax.xml.soap.Node) iter
368: .next();
369: appendSOAPNodeToDOMNode(document, result, childSOAPNode);
370: }
371: } else if (soapNode instanceof javax.xml.soap.Text) {
372: javax.xml.soap.Text textNode = (javax.xml.soap.Text) soapNode;
373: String textValue = textNode.getValue();
374:
375: // A text node can either be a comment or a real text node.
376: if (textNode.isComment())
377: result = document.createComment(textValue);
378: else
379: result = document.createTextNode(textValue);
380: } else {
381: // Not sure what to do here.
382: }
383:
384: return (result);
385: }
386:
387: /**
388: * Appends a SOAP Node to a DOM Node, by creating DOM Node objects to
389: * represent the same information in the SOAP Node. The Document object is
390: * needed as a factory to create DOM Node objects.
391: */
392: private void appendSOAPNodeToDOMNode(Document document,
393: org.w3c.dom.Node domNode, javax.xml.soap.Node soapNode)
394: throws ParserConfigurationException {
395: org.w3c.dom.Node newDOMNode = createDOMNodeFromSOAPNode(
396: soapNode, document);
397:
398: // Now that the new element is completely constructed (including its
399: // children), add it to the parent element.
400:
401: domNode.appendChild(newDOMNode);
402: }
403:
404: private static void dump(Source source) throws Exception {
405: TransformerFactory tf = TransformerFactory.newInstance();
406: Transformer t = tf.newTransformer();
407: StreamResult stdOut = new StreamResult(System.out);
408:
409: System.out.println("[BEGIN_MESSAGE_DUMP]");
410: t.transform(source, stdOut);
411: System.out.println("[END_MESSAGE_DUMP]");
412: }
413:
414: /**
415: * Extracts request/response payload from the soap body.
416: *
417: * @param soapBody soap body message.
418: * @param operation operation requested.
419: * @param isFault boolean indicating if it is a fault.
420: *
421: * @return request payload
422: *
423: * @throws JBIException - if request could not be extracted.
424: */
425: protected Node extractPayload(SOAPBody soapBody,
426: Operation operation, boolean isFault) throws JBIException {
427: mLogger.info(mStringTranslator
428: .getString("SBC_EXTRACT_REQUEST_PAYLOAD"));
429:
430: return getChildElement(soapBody);
431: }
432:
433: /**
434: * Used to check if the response code corresponds to a fault.
435: *
436: * @param responseCode response code
437: *
438: * @return true if it is a fault; false otherwise.
439: */
440: public boolean isFault(int responseCode) {
441: return false;
442: }
443:
444: /**
445: * Extracts the first Element node from the parent node.
446: *
447: * @param parentNode parent node
448: *
449: * @return first child element node.
450: */
451: private Node getChildElement(Node parentNode) {
452: NodeList childNodes = parentNode.getChildNodes();
453: Node currentNode = null;
454: Node elementNode = null;
455:
456: for (int i = 0; i < childNodes.getLength(); i++) {
457: currentNode = childNodes.item(i);
458:
459: if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
460: elementNode = currentNode;
461:
462: break;
463: }
464: }
465:
466: return elementNode;
467: }
468:
469: /**
470: * Extracts the fault code from the String.
471: *
472: * @param completeFaultCode fault code containing the namespace prefix and the code.
473: *
474: * @return the fault code without the namespace prefix
475: */
476: private String extractFaultCode(String completeFaultCode) {
477: String faultCode;
478: StringTokenizer tokenizer = new StringTokenizer(
479: completeFaultCode, ":");
480: if (tokenizer.countTokens() == 1) {
481: faultCode = completeFaultCode;
482: } else {
483: // Discard the first token which is hte namespace prefix.
484: tokenizer.nextToken();
485: faultCode = tokenizer.nextToken();
486: }
487: return faultCode;
488: }
489:
490: /**
491: * Normalizes the attachments sent as part of the SoapMessage.
492: *
493: * @param soapMessage soap Message
494: * @param normalizedMessage normalized Message
495: *
496: * @throws SOAPException if soap message cannot be read
497: * @throws MessagingException if attachments cannot be added to normalized message.
498: */
499: private void normalizeAttachments(SOAPMessage soapMessage,
500: NormalizedMessage normalizedMessage) throws SOAPException,
501: MessagingException {
502: if (soapMessage != null) {
503: if (soapMessage.countAttachments() > 0) {
504: Iterator attachmentIter = soapMessage.getAttachments();
505: for (; attachmentIter.hasNext();) {
506: AttachmentPart attachment = (AttachmentPart) attachmentIter
507: .next();
508: DataHandler dataHandler = attachment
509: .getDataHandler();
510: String contentId = attachment.getContentId();
511: normalizedMessage.addAttachment(contentId,
512: dataHandler);
513: }
514: }
515: }
516: }
517: }
|