001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.camel.component.cxf.jaxrs;
019
020 import java.lang.reflect.Method;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024
025 import javax.ws.rs.core.MultivaluedMap;
026 import javax.ws.rs.core.Response;
027
028 import org.apache.camel.Exchange;
029 import org.apache.camel.Message;
030 import org.apache.camel.component.cxf.CxfConstants;
031 import org.apache.camel.spi.HeaderFilterStrategy;
032 import org.apache.camel.spi.HeaderFilterStrategyAware;
033 import org.apache.commons.logging.Log;
034 import org.apache.commons.logging.LogFactory;
035 import org.apache.cxf.jaxrs.impl.MetadataMap;
036 import org.apache.cxf.jaxrs.model.OperationResourceInfoStack;
037 import org.apache.cxf.message.MessageContentsList;
038
039 /**
040 * Default strategy to bind between Camel and CXF exchange for RESTful resources.
041 *
042 *
043 * @version $Revision: 18533 $
044 */
045 public class DefaultCxfRsBinding implements CxfRsBinding, HeaderFilterStrategyAware {
046 private static final Log LOG = LogFactory.getLog(DefaultCxfRsBinding.class);
047
048 protected Map<String, String> camelToCxfHeaderMap = new HashMap<String, String>();
049 protected Map<String, String> cxfToCamelHeaderMap = new HashMap<String, String>();
050
051 private HeaderFilterStrategy headerFilterStrategy;
052
053 public DefaultCxfRsBinding() {
054 // initialize mappings between Camel and CXF header names
055
056 camelToCxfHeaderMap.put(Exchange.HTTP_URI, org.apache.cxf.message.Message.REQUEST_URI);
057 camelToCxfHeaderMap.put(Exchange.HTTP_METHOD, org.apache.cxf.message.Message.HTTP_REQUEST_METHOD);
058 camelToCxfHeaderMap.put(Exchange.HTTP_PATH, org.apache.cxf.message.Message.PATH_INFO);
059 camelToCxfHeaderMap.put(Exchange.CONTENT_TYPE, org.apache.cxf.message.Message.CONTENT_TYPE);
060 camelToCxfHeaderMap.put(Exchange.HTTP_CHARACTER_ENCODING, org.apache.cxf.message.Message.ENCODING);
061 camelToCxfHeaderMap.put(Exchange.HTTP_QUERY, org.apache.cxf.message.Message.QUERY_STRING);
062 camelToCxfHeaderMap.put(Exchange.ACCEPT_CONTENT_TYPE, org.apache.cxf.message.Message.ACCEPT_CONTENT_TYPE);
063
064 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.REQUEST_URI, Exchange.HTTP_URI);
065 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.HTTP_REQUEST_METHOD, Exchange.HTTP_METHOD);
066 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.PATH_INFO, Exchange.HTTP_PATH);
067 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.CONTENT_TYPE, Exchange.CONTENT_TYPE);
068 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.ENCODING, Exchange.HTTP_CHARACTER_ENCODING);
069 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.QUERY_STRING, Exchange.HTTP_QUERY);
070 cxfToCamelHeaderMap.put(org.apache.cxf.message.Message.ACCEPT_CONTENT_TYPE, Exchange.ACCEPT_CONTENT_TYPE);
071 }
072
073 public Object populateCxfRsResponseFromExchange(Exchange camelExchange,
074 org.apache.cxf.message.Exchange cxfExchange) throws Exception {
075 if (camelExchange.isFailed()) {
076 throw camelExchange.getException();
077 }
078
079 return camelExchange.getOut().getBody();
080 }
081
082
083 public void populateExchangeFromCxfRsRequest(org.apache.cxf.message.Exchange cxfExchange,
084 Exchange camelExchange, Method method, Object[] paramArray) {
085 Message camelMessage = camelExchange.getIn();
086 //Copy the CXF message header into the Camel inMessage
087 org.apache.cxf.message.Message cxfMessage = cxfExchange.getInMessage();
088
089 // TODO use header filter strategy and cxfToCamelHeaderMap
090
091 copyMessageHeader(cxfMessage, camelMessage, org.apache.cxf.message.Message.REQUEST_URI, Exchange.HTTP_URI);
092
093 copyMessageHeader(cxfMessage, camelMessage, org.apache.cxf.message.Message.HTTP_REQUEST_METHOD, Exchange.HTTP_METHOD);
094
095 // We need remove the BASE_PATH from the PATH_INFO
096 String pathInfo = (String)cxfMessage.get(org.apache.cxf.message.Message.PATH_INFO);
097 String basePath = (String)cxfMessage.get(org.apache.cxf.message.Message.BASE_PATH);
098 if (pathInfo != null && basePath != null && pathInfo.startsWith(basePath)) {
099 pathInfo = pathInfo.substring(basePath.length());
100 }
101 if (pathInfo != null) {
102 camelMessage.setHeader(Exchange.HTTP_PATH, pathInfo);
103 }
104
105 copyMessageHeader(cxfMessage, camelMessage, org.apache.cxf.message.Message.CONTENT_TYPE, Exchange.CONTENT_TYPE);
106
107 copyMessageHeader(cxfMessage, camelMessage, org.apache.cxf.message.Message.ENCODING, Exchange.HTTP_CHARACTER_ENCODING);
108
109 copyMessageHeader(cxfMessage, camelMessage, org.apache.cxf.message.Message.QUERY_STRING, Exchange.HTTP_QUERY);
110
111 copyMessageHeader(cxfMessage, camelMessage, org.apache.cxf.message.Message.ACCEPT_CONTENT_TYPE, Exchange.ACCEPT_CONTENT_TYPE);
112
113 camelMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, method.getReturnType());
114
115 camelMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_GENERIC_TYPE, method.getGenericReturnType());
116
117 copyOperationResourceInfoStack(cxfMessage, camelMessage);
118
119 camelMessage.setHeader(CxfConstants.OPERATION_NAME, method.getName());
120
121 camelMessage.setBody(new MessageContentsList(paramArray));
122 }
123
124
125 public MultivaluedMap<String, String> bindCamelHeadersToRequestHeaders(Map<String, Object> camelHeaders,
126 Exchange camelExchange)
127 throws Exception {
128
129 MultivaluedMap<String, String> answer = new MetadataMap<String, String>();
130 for (Map.Entry<String, Object> entry : camelHeaders.entrySet()) {
131
132 if (headerFilterStrategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), camelExchange)) {
133 if (LOG.isTraceEnabled()) {
134 LOG.trace("Drop Camel header: " + entry.getKey() + "=" + entry.getValue());
135 }
136 continue;
137 }
138
139 String mappedHeaderName = camelToCxfHeaderMap.get(entry.getKey());
140 if (mappedHeaderName == null) {
141 mappedHeaderName = entry.getKey();
142 }
143
144 if (LOG.isTraceEnabled()) {
145 LOG.trace("Propagate Camel header: " + entry.getKey() + "=" + entry.getValue() + " as "
146 + mappedHeaderName);
147 }
148
149 answer.putSingle(mappedHeaderName, entry.getValue().toString());
150 }
151 return answer;
152 }
153
154 /**
155 * This method call Message.getBody({@link MessageContentsList}) to allow
156 * an appropriate converter to kick in even through we only read the first
157 * element off the MessageContextList. If that returns null, we check
158 * the body to see if it is a List or an array and then return the first
159 * element. If that fails, we will simply return the object.
160 */
161 public Object bindCamelMessageBodyToRequestBody(Message camelMessage, Exchange camelExchange)
162 throws Exception {
163
164 Object request = camelMessage.getBody(MessageContentsList.class);
165 if (request != null) {
166 return ((MessageContentsList)request).get(0);
167 }
168
169 request = camelMessage.getBody();
170 if (request instanceof List) {
171 request = ((List<?>)request).get(0);
172 } else if (request.getClass().isArray()) {
173 request = ((Object[])request)[0];
174 }
175
176 return request;
177
178 }
179
180 /**
181 * We will return an empty Map unless the response parameter is a {@link Response} object.
182 */
183 public Map<String, Object> bindResponseHeadersToCamelHeaders(Object response, Exchange exchange)
184 throws Exception {
185
186 Map<String, Object> answer = new HashMap<String, Object>();
187 if (response instanceof Response) {
188
189 for (Map.Entry<String, List<Object>> entry : ((Response)response).getMetadata().entrySet()) {
190 if (!headerFilterStrategy.applyFilterToExternalHeaders(entry.getKey(),
191 entry.getValue(), exchange)) {
192
193 String mappedHeaderName = cxfToCamelHeaderMap.get(entry.getKey());
194 if (mappedHeaderName == null) {
195 mappedHeaderName = entry.getKey();
196 }
197
198 if (LOG.isTraceEnabled()) {
199 LOG.trace("Populate external header " + entry.getKey() + "=" + entry.getValue()
200 + " as " + mappedHeaderName);
201 }
202
203 answer.put(mappedHeaderName, entry.getValue().get(0));
204
205 } else {
206 if (LOG.isTraceEnabled()) {
207 LOG.trace("Drop external header " + entry.getKey() + "=" + entry.getValue());
208 }
209 }
210 }
211
212 // put response code in Camel message header
213 answer.put(Exchange.HTTP_RESPONSE_CODE, ((Response)response).getStatus());
214 }
215
216 return answer;
217 }
218
219 /**
220 * By default, we just return the response object.
221 */
222 public Object bindResponseToCamelBody(Object response, Exchange camelExchange) throws Exception {
223 return response;
224 }
225
226 public HeaderFilterStrategy getHeaderFilterStrategy() {
227 return headerFilterStrategy;
228 }
229
230
231 public void setHeaderFilterStrategy(HeaderFilterStrategy strategy) {
232 headerFilterStrategy = strategy;
233 }
234
235 public Map<String, String> getCamelToCxfHeaderMap() {
236 return camelToCxfHeaderMap;
237 }
238
239 public void setCamelToCxfHeaderMap(Map<String, String> camelToCxfHeaderMap) {
240 this.camelToCxfHeaderMap = camelToCxfHeaderMap;
241 }
242
243 public Map<String, String> getCxfToCamelHeaderMap() {
244 return cxfToCamelHeaderMap;
245 }
246
247 public void setCxfToCamelHeaderMap(Map<String, String> cxfToCamelHeaderMap) {
248 this.cxfToCamelHeaderMap = cxfToCamelHeaderMap;
249 }
250
251 protected void copyMessageHeader(org.apache.cxf.message.Message cxfMessage, Message camelMessage, String cxfKey, String camelKey) {
252 if (cxfMessage.get(cxfKey) != null) {
253 camelMessage.setHeader(camelKey, cxfMessage.get(cxfKey));
254 }
255 }
256
257 protected void copyOperationResourceInfoStack(org.apache.cxf.message.Message cxfMessage, Message camelMessage) {
258 OperationResourceInfoStack stack = cxfMessage.get(OperationResourceInfoStack.class);
259 if (stack != null) {
260 // make a copy of the operation resource info for looking up the sub resource location
261 OperationResourceInfoStack copyStack = (OperationResourceInfoStack)stack.clone();
262 camelMessage.setHeader(CxfConstants.CAMEL_CXF_RS_OPERATION_RESOURCE_INFO_STACK, copyStack);
263
264 }
265
266 }
267
268 }