View Javadoc
1   /*
2    * Copyright 2010 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.platform.camel.ihe.ws;
17  
18  import static org.apache.cxf.message.Message.PROTOCOL_HEADERS;
19  
20  import java.util.*;
21  import java.util.function.Supplier;
22  
23  import javax.xml.namespace.QName;
24  
25  import org.apache.camel.Message;
26  import org.apache.cxf.headers.Header;
27  import org.apache.cxf.helpers.CastUtils;
28  import org.apache.cxf.jaxws.context.WrappedMessageContext;
29  
30  /**
31   * Utilities for handling HTTP and SOAP headers in Web Service interactions.
32   * @author Dmytro Rud
33   */
34  abstract public class HeaderUtils {
35      
36      private HeaderUtils() {
37          throw new IllegalStateException("Cannot instantiate utility class");
38      }
39  
40  
41      public static void processIncomingHeaders(
42              Map<String, Object> messageContext, 
43              Message message) 
44      {
45          processIncomingHttpHeaders(messageContext, message);
46          processIncomingSoapHeaders(messageContext, message);
47      }
48  
49  
50      public static void processUserDefinedOutgoingHeaders(
51              Map<String, Object> messageContext, 
52              Message message,
53              boolean isRequest) 
54      {
55          processUserDefinedOutgoingHttpHeaders(messageContext, message, isRequest);
56          processUserDefinedOutgoingSoapHeaders(messageContext, message, isRequest);
57      }
58  
59  
60      /**
61       * Returns headers of the message represented by the given context.
62       * 
63       * @param <T>
64       *      type of headers' container.
65       * @param messageContext
66       *      Web Service message context.
67       * @param key
68       *      key under which the headers reside in the message context. 
69       * @param useInputMessage
70       *      whether input message should the used.
71       * @param needCreateWhenNotExist
72       *      whether the headers' map should be created when it does 
73       *      not exist.
74       * @param defaultValueFactory
75       *      factory for producing default values.
76       * @return
77       *      either the map of HTTP headers as found in the message context,
78       *      or a newly created map when none found, or <code>null</code> 
79       *      when creation of a new map is not allowed. 
80       */
81      @SuppressWarnings("unchecked")
82      public static <T> T getHeaders(
83              Map<String, Object> messageContext,
84              String key,
85              boolean useInputMessage,
86              boolean needCreateWhenNotExist, 
87              Supplier<T> defaultValueFactory)
88      {
89          WrappedMessageContext wrappedContext = (WrappedMessageContext) messageContext;
90          Map<String, Object> headersContainer = useInputMessage
91              ? wrappedContext.getWrappedMap()
92              : wrappedContext.getWrappedMessage().getExchange().getOutMessage();
93          
94          T headers = (T) headersContainer.get(key);
95          if ((headers == null) && needCreateWhenNotExist) {
96              headers = defaultValueFactory.get();
97              headersContainer.put(key, headers);
98          }
99          return headers;
100     }
101 
102 
103     /**
104      * Stores a map of incoming SOAP headers from the given  
105      * Web Service message context into the Camel header
106      * {@link AbstractWsEndpoint#INCOMING_SOAP_HEADERS}
107      * of the given Camel message.
108      * 
109      * @param messageContext
110      *      Web Service message contents.
111      * @param message
112      *      Camel message in whose headers the 
113      *      SOAP headers should be stored.
114      */
115     private static void processIncomingSoapHeaders(
116             Map<String, Object> messageContext, 
117             Message message) 
118     {
119         HashMap<QName, Header> userHeaders = new HashMap<>();
120         List<Header> soapHeaders = getHeaders(
121                 messageContext, Header.HEADER_LIST, true, false, null);
122         if (soapHeaders != null) {
123             for (Header soapHeader : soapHeaders) {
124                 userHeaders.put(soapHeader.getName(), soapHeader);
125             }
126         }
127         message.setHeader(AbstractWsEndpoint.INCOMING_SOAP_HEADERS, userHeaders);
128     }
129 
130 
131     /**
132      * Injects user-defined SOAP headers from the header 
133      * {@link AbstractWsEndpoint#OUTGOING_SOAP_HEADERS}
134      * of the given Camel message into the given Web Service 
135      * message context.
136      * 
137      * @param messageContext
138      *      Web Service message contents.
139      * @param message
140      *      Camel message from whose headers the 
141      *      SOAP headers should be taken.
142      * @param isRequest
143      *      whether the Web Service message under consideration 
144      *      is a request one (<code>false</code> on server side, 
145      *      <code>true</code> on client side). 
146      */
147     @SuppressWarnings("unchecked")
148     private static void processUserDefinedOutgoingSoapHeaders(
149             Map<String, Object> messageContext, 
150             Message message,
151             boolean isRequest) 
152     {
153         Collection<Header> userHeaders = null;
154         Object o = message.getHeader(AbstractWsEndpoint.OUTGOING_SOAP_HEADERS);
155         if (o instanceof Collection) {
156             userHeaders = (Collection<Header>) o;
157         } else if (o instanceof Map) {
158             userHeaders = ((Map<QName, Header>) o).values();
159         }
160 
161         if ((userHeaders != null) && ! userHeaders.isEmpty()) {
162             List<Header> soapHeaders = getHeaders(
163                     messageContext, Header.HEADER_LIST, isRequest, true, ArrayList::new);
164             soapHeaders.addAll(userHeaders);
165        }
166     }
167 
168 
169     /**
170      * Stores a map of incoming HTTP headers from the given  
171      * Web Service message context into the Camel header
172      * {@link AbstractWsEndpoint#INCOMING_HTTP_HEADERS}
173      * of the given Camel message.
174      * 
175      * @param messageContext
176      *      Web Service message contents.
177      * @param message
178      *      Camel message in whose headers the 
179      *      HTTP headers should be stored.
180      */
181     private static void processIncomingHttpHeaders(
182             Map<String, Object> messageContext, 
183             Message message) 
184     {
185         Map<String, String> userHeaders = new HashMap<>();
186         Map<String, List<String>> httpHeaders = getHeaders(
187                 messageContext, PROTOCOL_HEADERS, true, false, null);
188         if (httpHeaders != null) {
189             for (Map.Entry<String, List<String>> entry : httpHeaders.entrySet()) {
190                 userHeaders.put(entry.getKey(), entry.getValue().get(0));
191             }
192         }
193         message.setHeader(AbstractWsEndpoint.INCOMING_HTTP_HEADERS, userHeaders);
194     }
195 
196 
197     /**
198      * Injects user-defined HTTP headers from the header 
199      * {@link AbstractWsEndpoint#OUTGOING_HTTP_HEADERS}
200      * of the given Camel message into the given Web Service 
201      * message context.
202      * 
203      * @param messageContext
204      *      Web Service message contents.
205      * @param message
206      *      Camel message from whose headers the 
207      *      HTTP headers should be taken.
208      * @param isRequest
209      *      whether the Web Service message under consideration 
210      *      is a request one (<code>false</code> on server side, 
211      *      <code>true</code> on client side). 
212      */
213     private static void processUserDefinedOutgoingHttpHeaders(
214             Map<String, Object> messageContext, 
215             Message message,
216             boolean isRequest) 
217     {
218         Map<String, String> headers = CastUtils.cast(
219                 message.getHeader(AbstractWsEndpoint.OUTGOING_HTTP_HEADERS, Map.class));
220         
221         if ((headers != null) && ! headers.isEmpty()) {
222             Map<String, List<String>> httpHeaders = getHeaders(
223                     messageContext, PROTOCOL_HEADERS, isRequest, true, HashMap::new);
224             for (Map.Entry<String, String> entry : headers.entrySet()) {
225                 httpHeaders.put(entry.getKey(), Collections.singletonList(entry.getValue()));
226             }
227         }
228     }
229 }