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.cxf.payload;
17  
18  import java.io.ByteArrayInputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.UnsupportedEncodingException;
22  
23  import org.apache.cxf.helpers.IOUtils;
24  import org.apache.cxf.interceptor.AttachmentInInterceptor;
25  import org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor;
26  import org.apache.cxf.interceptor.Fault;
27  import org.apache.cxf.interceptor.StaxInInterceptor;
28  import org.apache.cxf.message.Message;
29  import org.apache.cxf.phase.AbstractPhaseInterceptor;
30  import org.apache.cxf.phase.Phase;
31  import org.openehealth.ipf.commons.ihe.ws.utils.SoapUtils;
32  
33  import static org.openehealth.ipf.commons.ihe.ws.cxf.payload.StringPayloadHolder.PayloadType;
34  
35  
36  /**
37   * CXF interceptor that saves String payload of the incoming SOAP message
38   * body into the CXF message.  Usable on both client and server sides.
39   *
40   * @author Dmytro Rud
41   */
42  public class InPayloadExtractorInterceptor extends AbstractPhaseInterceptor<Message> {
43      private final PayloadType payloadType;
44  
45      public InPayloadExtractorInterceptor(PayloadType payloadType) {
46          super(InPayloadExtractorInterceptor.class.getName() + '-' + payloadType, getPhase(payloadType));
47          this.payloadType = payloadType;
48          switch (payloadType) {
49              case HTTP:
50                  addBefore(AttachmentInInterceptor.class.getName());
51                  break;
52              case SOAP_BODY:
53                  addAfter(AttachmentInInterceptor.class.getName());
54                  addBefore(StaxInInterceptor.class.getName());
55                  break;
56          }
57      }
58  
59  
60      private static String getPhase(PayloadType payloadType) {
61          switch (payloadType) {
62              case HTTP:
63                  return Phase.RECEIVE;
64              case SOAP_BODY:
65                  return Phase.PRE_STREAM;
66          }
67          throw new IllegalArgumentException("Unknown payload type " + payloadType);
68      }
69  
70  
71      @Override
72      public void handleMessage(Message message) {
73          if (isGET(message)) {
74              return;
75          }
76  
77          // extract current message contents from the stream,
78          // substitute the used stream by an again-usable one.
79          byte[] bytes;
80          try {
81              InputStream stream = message.getContent(InputStream.class);
82              bytes = IOUtils.readBytesFromStream(stream);
83              message.setContent(InputStream.class, new ByteArrayInputStream(bytes));
84          } catch (IOException e) {
85              throw new RuntimeException("Error when extracting payload", e);
86          }
87  
88          // optionally extract SOAP Body from the SOAP Envelope
89          String payload;
90          try {
91              String charsetName = (String) message.get(Message.ENCODING);
92              payload = (charsetName != null) ? new String(bytes, charsetName) : new String(bytes);
93          } catch (UnsupportedEncodingException e) {
94              // actually cannot occur, because non-supported encodings
95              // will cause exceptions a lot earlier
96              throw new RuntimeException(e);
97          }
98  
99          if (payloadType == PayloadType.SOAP_BODY) {
100             payload = SoapUtils.extractSoapBody(payload);
101         }
102 
103         // save the String payload into the message's content map
104         StringPayloadHolder payloadHolder = message.getContent(StringPayloadHolder.class);
105         if (payloadHolder == null) {
106             payloadHolder = new StringPayloadHolder();
107             message.setContent(StringPayloadHolder.class, payloadHolder);
108         }
109         payloadHolder.put(payloadType, payload);
110 
111         // optionally take care of dropping HTTP payload and
112         // input stream after the SOAP Body has been successfully parsed
113         if (payloadType == PayloadType.HTTP) {
114             message.getInterceptorChain().add(new DropHttpPayloadInterceptor());
115         }
116     }
117 
118 
119     /**
120      * Interceptor which deletes saved "whole-HTTP" payload and the byte
121      * array-based input stream, which are not necessary any more after
122      * the SOAP Body has been successfully processed by the
123      * {@link org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor}.
124      */
125     private static class DropHttpPayloadInterceptor extends AbstractPhaseInterceptor<Message> {
126 
127         private DropHttpPayloadInterceptor() {
128             super(Phase.UNMARSHAL);
129             addAfter(DocLiteralInInterceptor.class.getName());
130         }
131 
132         @Override
133         public void handleMessage(Message message) throws Fault {
134             StringPayloadHolder payloadHolder = message.getContent(StringPayloadHolder.class);
135             if (payloadHolder != null) {
136                 payloadHolder.remove(PayloadType.HTTP);
137             }
138             message.removeContent(InputStream.class);
139         }
140     }
141 }
142