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 package org.apache.camel.component.restlet;
018
019 import java.io.PrintWriter;
020 import java.io.StringWriter;
021 import java.util.Map;
022
023 import javax.xml.transform.dom.DOMSource;
024
025 import org.apache.camel.Exchange;
026 import org.apache.camel.Message;
027 import org.apache.camel.RuntimeCamelException;
028 import org.apache.camel.converter.jaxp.StringSource;
029 import org.apache.camel.spi.HeaderFilterStrategy;
030 import org.apache.camel.spi.HeaderFilterStrategyAware;
031 import org.apache.commons.logging.Log;
032 import org.apache.commons.logging.LogFactory;
033 import org.restlet.data.ChallengeResponse;
034 import org.restlet.data.ChallengeScheme;
035 import org.restlet.data.CharacterSet;
036 import org.restlet.data.Form;
037 import org.restlet.data.MediaType;
038 import org.restlet.data.Method;
039 import org.restlet.data.Request;
040 import org.restlet.data.Response;
041 import org.restlet.data.Status;
042
043 /**
044 * Default Restlet binding implementation
045 *
046 * @version $Revision: 19261 $
047 */
048 public class DefaultRestletBinding implements RestletBinding, HeaderFilterStrategyAware {
049 private static final Log LOG = LogFactory.getLog(DefaultRestletBinding.class);
050 private HeaderFilterStrategy headerFilterStrategy;
051
052 public void populateExchangeFromRestletRequest(Request request, Exchange exchange) throws Exception {
053 Message inMessage = exchange.getIn();
054
055 // extract headers from restlet
056 for (Map.Entry<String, Object> entry : request.getAttributes().entrySet()) {
057 if (!headerFilterStrategy.applyFilterToExternalHeaders(entry.getKey(), entry.getValue(), exchange)) {
058 inMessage.setHeader(entry.getKey(), entry.getValue());
059 if (LOG.isDebugEnabled()) {
060 LOG.debug("Populate exchange from Restlet request header: "
061 + entry.getKey() + " value: " + entry.getValue());
062 }
063 }
064 }
065
066 // copy query string to header
067 String query = request.getResourceRef().getQuery();
068 if (query != null) {
069 inMessage.setHeader(Exchange.HTTP_QUERY, query);
070 }
071
072 // copy URI to header
073 inMessage.setHeader(Exchange.HTTP_URI, request.getResourceRef().getIdentifier(true));
074
075 // copy HTTP method to header
076 inMessage.setHeader(Exchange.HTTP_METHOD, request.getMethod().toString());
077
078 if (!request.isEntityAvailable()) {
079 return;
080 }
081
082
083
084 // only deal with the form if the content type is "application/x-www-form-urlencoded"
085 if (request.getEntity().getMediaType().equals(MediaType.APPLICATION_WWW_FORM)) {
086 Form form = new Form(request.getEntity());
087 for (Map.Entry<String, String> entry : form.getValuesMap().entrySet()) {
088 if (entry.getValue() == null) {
089 inMessage.setBody(entry.getKey());
090 if (LOG.isDebugEnabled()) {
091 LOG.debug("Populate exchange from Restlet request body: " + entry.getValue());
092 }
093 } else {
094 if (!headerFilterStrategy.applyFilterToExternalHeaders(entry.getKey(), entry.getValue(), exchange)) {
095 inMessage.setHeader(entry.getKey(), entry.getValue());
096 if (LOG.isDebugEnabled()) {
097 LOG.debug("Populate exchange from Restlet request user header: "
098 + entry.getKey() + " value: " + entry.getValue());
099 }
100 }
101 }
102 }
103 } else {
104 inMessage.setBody(request.getEntity().getStream());
105 }
106
107 }
108
109 public void populateRestletRequestFromExchange(Request request, Exchange exchange) {
110 request.setReferrerRef("camel-restlet");
111 String body = exchange.getIn().getBody(String.class);
112 Form form = new Form();
113 // add the body as the key in the form with null value
114 form.add(body, null);
115
116 MediaType mediaType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, MediaType.class);
117 if (mediaType == null) {
118 mediaType = MediaType.APPLICATION_WWW_FORM;
119 }
120
121 if (LOG.isDebugEnabled()) {
122 LOG.debug("Populate Restlet request from exchange body: " + body + " using media type " + mediaType);
123 }
124
125 // login and password are filtered by header filter strategy
126 String login = exchange.getIn().getHeader(RestletConstants.RESTLET_LOGIN, String.class);
127 String password = exchange.getIn().getHeader(RestletConstants.RESTLET_PASSWORD, String.class);
128
129 if (login != null && password != null) {
130 ChallengeResponse authentication = new ChallengeResponse(ChallengeScheme.HTTP_BASIC, login, password);
131 request.setChallengeResponse(authentication);
132 if (LOG.isDebugEnabled()) {
133 LOG.debug("Basic HTTP Authentication has been applied");
134 }
135 }
136
137 for (Map.Entry<String, Object> entry : exchange.getIn().getHeaders().entrySet()) {
138 if (!headerFilterStrategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), exchange)) {
139 // Use forms only for GET and POST/x-www-form-urlencoded
140 if (request.getMethod() == Method.GET || (request.getMethod() == Method.POST && mediaType == MediaType.APPLICATION_WWW_FORM)) {
141 if (entry.getKey().startsWith("org.restlet.")) {
142 // put the org.restlet headers in attributes
143 request.getAttributes().put(entry.getKey(), entry.getValue());
144 } else {
145 // put the user stuff in the form
146 form.add(entry.getKey(), entry.getValue().toString());
147 }
148 } else {
149 // For non-form post put all the headers in attributes
150 request.getAttributes().put(entry.getKey(), entry.getValue());
151 }
152 if (LOG.isDebugEnabled()) {
153 LOG.debug("Populate Restlet request from exchange header: "
154 + entry.getKey() + " value: " + entry.getValue());
155 }
156 }
157 }
158
159 if (LOG.isDebugEnabled()) {
160 LOG.debug("Using Content Type: "
161 + mediaType + " for POST data: " + body);
162 }
163
164 // Only URL Encode for GET and form POST
165 if (request.getMethod() == Method.GET || (request.getMethod() == Method.POST && mediaType == MediaType.APPLICATION_WWW_FORM)) {
166 request.setEntity(form.getWebRepresentation());
167 } else {
168 request.setEntity(body, mediaType);
169 }
170 }
171
172 public void populateRestletResponseFromExchange(Exchange exchange, Response response) {
173
174 Message out;
175 if (exchange.isFailed()) {
176 // 500 for internal server error which can be overridden by response code in header
177 response.setStatus(Status.valueOf(500));
178 if (exchange.hasOut() && exchange.getOut().isFault()) {
179 out = exchange.getOut();
180 } else {
181 // print exception as message and stacktrace
182 Exception t = exchange.getException();
183 StringWriter sw = new StringWriter();
184 PrintWriter pw = new PrintWriter(sw);
185 t.printStackTrace(pw);
186 response.setEntity(sw.toString(), MediaType.TEXT_PLAIN);
187 return;
188 }
189 } else {
190 out = exchange.getOut();
191 }
192
193 // get content type
194 MediaType mediaType = out.getHeader(Exchange.CONTENT_TYPE, MediaType.class);
195 if (mediaType == null) {
196 Object body = out.getBody();
197 mediaType = MediaType.TEXT_PLAIN;
198 if (body instanceof String) {
199 mediaType = MediaType.TEXT_PLAIN;
200 } else if (body instanceof StringSource || body instanceof DOMSource) {
201 mediaType = MediaType.TEXT_XML;
202 }
203 }
204
205 // get response code
206 Integer responseCode = out.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
207 if (responseCode != null) {
208 response.setStatus(Status.valueOf(responseCode));
209 }
210
211 for (Map.Entry<String, Object> entry : out.getHeaders().entrySet()) {
212 if (!headerFilterStrategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), exchange)) {
213 response.getAttributes().put(entry.getKey(), entry.getValue());
214 if (LOG.isDebugEnabled()) {
215 LOG.debug("Populate Restlet response from exchange header: "
216 + entry.getKey() + " value: " + entry.getValue());
217 }
218 }
219 }
220
221 String text = out.getBody(String.class);
222 if (LOG.isDebugEnabled()) {
223 LOG.debug("Populate Restlet response from exchange body: " + text);
224 }
225 response.setEntity(text, mediaType);
226
227 if (exchange.getProperty(Exchange.CHARSET_NAME) != null) {
228 response.getEntity().setCharacterSet(CharacterSet.valueOf(exchange.getProperty(Exchange.CHARSET_NAME,
229 String.class)));
230 }
231 }
232
233 public void populateExchangeFromRestletResponse(Exchange exchange, Response response) throws Exception {
234
235 for (Map.Entry<String, Object> entry : response.getAttributes().entrySet()) {
236 if (!headerFilterStrategy.applyFilterToExternalHeaders(entry.getKey(), entry.getValue(), exchange)) {
237 exchange.getOut().setHeader(entry.getKey(), entry.getValue());
238 if (LOG.isDebugEnabled()) {
239 LOG.debug("Populate exchange from Restlet response header: "
240 + entry.getKey() + " value: " + entry.getValue());
241 }
242 }
243 }
244
245 String text = response.getEntity().getText();
246 if (LOG.isDebugEnabled()) {
247 LOG.debug("Populate exchange from Restlet response: " + text);
248 }
249
250 if (exchange.getPattern().isOutCapable()) {
251 exchange.getOut().setBody(text);
252 } else {
253 throw new RuntimeCamelException("Exchange is incapable of receiving response: " + exchange + " with pattern: " + exchange.getPattern());
254 }
255 }
256
257 public HeaderFilterStrategy getHeaderFilterStrategy() {
258 return headerFilterStrategy;
259 }
260
261 public void setHeaderFilterStrategy(HeaderFilterStrategy strategy) {
262 headerFilterStrategy = strategy;
263 }
264 }