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 java.util.HashMap;
19  import java.util.Map;
20  import javax.xml.ws.handler.MessageContext;
21  
22  import org.apache.camel.Exchange;
23  import org.apache.camel.ExchangePattern;
24  import org.apache.cxf.jaxws.context.WebServiceContextImpl;
25  import org.apache.cxf.ws.addressing.AddressingProperties;
26  import org.apache.cxf.ws.addressing.JAXWSAConstants;
27  import org.openehealth.ipf.commons.ihe.ws.correlation.AsynchronyCorrelator;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  /**
32   * Base class for receivers of asynchronous responses for Web Service-based IHE transactions.
33   * @author Dmytro Rud
34   */
35  abstract public class AbstractAsyncResponseWebService extends AbstractWebService {
36      private static final transient Logger LOG = LoggerFactory.getLogger(AbstractAsyncResponseWebService.class);
37  
38      /**
39       * Determines whether correlation items related to the given message can be dropped.
40       * <p>
41       * Per default, always returns <code>true</code>.
42       * @param response
43       *      response message.
44       * @return
45       *      <code>true</code> when correlation items related
46       *      to the given message can be dropped.
47       */
48      protected boolean canDropCorrelation(Object response) {
49          return true;
50      }
51  
52  
53      /**
54       * Before calling the base method, determines correlation key  
55       * and stores it into message headers. 
56       */
57      @SuppressWarnings("unchecked")
58      @Override
59      protected Exchange process(
60              Object body, 
61              Map<String, Object> headers,
62              ExchangePattern exchangePattern) 
63      {
64          final AsynchronyCorrelator correlator = getConsumer().getEndpoint().getCorrelator();
65  
66          MessageContext messageContext = new WebServiceContextImpl().getMessageContext();
67          AddressingProperties apropos = (AddressingProperties) messageContext.get(JAXWSAConstants.ADDRESSING_PROPERTIES_INBOUND);
68          String messageId = ((apropos != null) && (apropos.getRelatesTo() != null))
69                  ? apropos.getRelatesTo().getValue()
70                  : null;
71  
72          // when no ReplyTo header found -- try alternative keys
73          if (messageId == null) {
74              String[] alternativeKeys = getAlternativeResponseKeys(body);
75              if (alternativeKeys != null) {
76                  for (String key : alternativeKeys) {
77                      messageId = correlator.getMessageId(key);
78                      if (messageId != null) {
79                          break;
80                      }
81                  }
82              }
83          }
84  
85          if (messageId != null) {
86              // expose user-defined correlation key as message header
87              String correlationKey = correlator.getCorrelationKey(messageId);
88              if (correlationKey != null) {
89                  if (headers == null) {
90                      // NB: it shouldn't be a non-modifiable singleton map...
91                      headers = new HashMap<>();
92                  }
93                  headers.put(AbstractWsEndpoint.CORRELATION_KEY_HEADER_NAME, correlationKey);
94              }
95  
96              // drop correlation data when appropriate
97              if (canDropCorrelation(body)) {
98                  correlator.delete(messageId);
99              }
100         } else {
101             LOG.error("Cannot retrieve WSA RelatesTo header, message correlation not possible");
102         }
103 
104         return super.process(body, headers, exchangePattern);
105     }
106 
107 
108     /**
109      * Determines the set of correlation keys for the given response message,
110      * which are alternative to the WS-Addressing message ID referenced in the
111      * &lt;ReplyTo&gt; header.
112      * An example of alternative key is the query ID in HL7v3-based transactions.
113      * <p>
114      * Per default, this method returns <code>null</code>.
115      *
116      * @param response
117      *      response message.
118      * @return
119      *      A non-empty collection of non-<code>null</code> alternative keys,
120      *      or <code>null</code>, when no keys could have been extracted.
121      */
122     protected String[] getAlternativeResponseKeys(Object response) {
123         return null;
124     }
125 }
126