View Javadoc
1   /*
2    * Copyright 2009 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *     
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.openehealth.ipf.commons.ihe.ws.utils;
17  
18  import org.slf4j.Logger;
19  import org.slf4j.LoggerFactory;
20  import org.apache.cxf.binding.soap.Soap11;
21  import org.apache.cxf.binding.soap.Soap12;
22  import org.apache.cxf.message.Exchange;
23  import org.apache.cxf.message.Message;
24  import org.apache.cxf.ws.addressing.Names;
25  import org.apache.cxf.ws.addressing.VersionTransformer.Names200403;
26  import org.apache.cxf.ws.addressing.VersionTransformer.Names200408;
27  import org.w3c.dom.Element;
28  import org.w3c.dom.Node;
29  
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.Set;
33  
34  /**
35   * Generic constants and subroutines for SOAP/XML processing.
36   * @author Dmytro Rud
37   */
38  public abstract class SoapUtils {
39      private static final transient Logger LOG = LoggerFactory.getLogger(SoapUtils.class);
40  
41      private SoapUtils() {
42          throw new UnsupportedOperationException("Utility class cannot be instantiated");
43      }
44  
45      /* --------------------------------------- */
46      /*      XML/SOAP processing constants      */
47      /* --------------------------------------- */
48  
49      /**
50       * Set of URIs corresponding to supported WS-Addressing specification versions.
51       */
52      public static final Set<String> WS_ADDRESSING_NS_URIS;
53  
54      /**
55       * Set of URIs corresponding to supported SOAP versions.
56       */
57      public static final Set<String> SOAP_NS_URIS;
58  
59      static {
60          WS_ADDRESSING_NS_URIS = new HashSet<>();
61          WS_ADDRESSING_NS_URIS.add(Names.WSA_NAMESPACE_NAME);
62          WS_ADDRESSING_NS_URIS.add(Names200403.WSA_NAMESPACE_NAME);
63          WS_ADDRESSING_NS_URIS.add(Names200408.WSA_NAMESPACE_NAME);
64  
65          SOAP_NS_URIS = new HashSet<>();
66          SOAP_NS_URIS.add(Soap11.SOAP_NAMESPACE);
67          SOAP_NS_URIS.add(Soap12.SOAP_NAMESPACE);
68      }
69  
70  
71      /**
72       * Extracts the proper body (for example, a Query) from the
73       * SOAP envelope, both represented as Strings.
74       * <p>
75       * Does really suppose that the given String contains
76       * a SOAP envelope and not check it thoroughly.
77       *
78       * @param soapEnvelope
79       *      The SOAP Envelope (XML document) as String.
80       * @return
81       *      Extracted SOAP Body contents as String, or the original
82       *      parameter when it does not seem to represent a valid
83       *      SOAP envelope.
84       */
85      public static String extractSoapBody(String soapEnvelope) {
86          try {
87              /*
88               * We search for following positions (variables posXX):
89               *
90               *    <S:Envelope><S:Body>the required information</S:Body><S:Envelope>
91               *                3      4                        1  2    5
92               *
93               *
94               *    <Envelope><Body>the required information</Body><Envelope>
95               *   2                                        1     5
96               *
97               */
98              int pos1, pos2, pos3, pos4, pos5;
99              pos1 = soapEnvelope.lastIndexOf("<");
100             pos1 = soapEnvelope.lastIndexOf("<", pos1 - 1);
101             pos5 = soapEnvelope.indexOf(">", pos1);
102             if (soapEnvelope.charAt(pos5 - 1) == '/') {
103                 return "";
104             }
105             pos2 = soapEnvelope.indexOf(":", pos1);
106             String soapPrefix = ((pos2 == -1) || (pos5 < pos2)) ?
107                     "" : soapEnvelope.substring(pos1 + 2, pos2 + 1);
108             String bodyElementStart = "<" + soapPrefix + "Body";
109             pos3 = soapEnvelope.indexOf(bodyElementStart);
110             pos4 = soapEnvelope.indexOf('>', pos3 + bodyElementStart.length());
111             return soapEnvelope.substring(pos4 + 1, pos1);
112 
113         } catch(Exception e) {
114             LOG.error("Invalid contents, probably not a SOAP Envelope in the parameter", e);
115             return soapEnvelope;
116         }
117     }
118 
119 
120     /**
121      * Returns Exception object from the outgoing fault message contained in the given
122      * CXF exchange, or <code>null</code>, when no exception could be extracted.
123      */
124     public static Exception extractOutgoingException(Exchange exchange) {
125         Message outFaultMessage = exchange.getOutFaultMessage();
126         return (outFaultMessage != null) ? outFaultMessage.getContent(Exception.class) : null;
127     }
128 
129 
130     /**
131      * Returns String payload of the outgoing message contained in the given
132      * CXF exchange, or <code>null</code>, when no String payload could be extracted.
133      */
134     public static String extractOutgoingPayload(Exchange exchange) {
135         try {
136             return (String) exchange.getOutMessage().getContent(List.class).get(0);
137         } catch (Exception e) {
138             return null;
139         }
140     }
141 
142     /**
143      * Searches for the first sub-element of the given XML element, which has
144      * the given local name and whose namespace belongs to the given set.
145      *
146      * @param root            an XML element whose children will be iterated, null values are allowed
147      * @param nsUris          a set of namespace URIs the wanted element can belong to
148      * @param wantedLocalName local name of the wanted element
149      * @return corresponding child element or <code>null</code> when none found
150      */
151     public static Element getElementNS(
152             Element root,
153             Set<String> nsUris,
154             String wantedLocalName)
155     {
156         if (root == null) {
157             return null;
158         }
159 
160         Node node = root.getFirstChild();
161         while (node != null) {
162             if ((node instanceof Element) &&
163                     nsUris.contains(node.getNamespaceURI()) &&
164                     node.getLocalName().equals(wantedLocalName)) {
165                 return (Element) node;
166             }
167 
168             node = node.getNextSibling();
169         }
170 
171         return null;
172     }
173 }