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.gae.task;
018
019 import javax.servlet.http.HttpServletRequest;
020 import javax.servlet.http.HttpServletResponse;
021
022 import com.google.appengine.api.labs.taskqueue.TaskOptions;
023
024 import org.apache.camel.Exchange;
025 import org.apache.camel.Message;
026 import org.apache.camel.component.gae.bind.InboundBinding;
027 import org.apache.camel.component.gae.bind.OutboundBinding;
028 import org.apache.camel.component.http.DefaultHttpBinding;
029 import org.apache.camel.component.http.HttpMessage;
030 import org.apache.camel.spi.HeaderFilterStrategy;
031
032 /**
033 * Binds the {@link TaskOptions} of the task queueing service to a Camel
034 * {@link Exchange} for outbound communication. For inbound communication a
035 * {@link HttpMessage} is bound to {@link Exchange}.
036 */
037 public class GTaskBinding implements
038 OutboundBinding <GTaskEndpoint, TaskOptions, Void>,
039 InboundBinding <GTaskEndpoint, HttpServletRequest, HttpServletResponse> {
040
041 /**
042 * Camel header name corresponding to <code>X-AppEngine-QueueName</code>
043 * header created by task queueing service.
044 */
045 public static final String GTASK_QUEUE_NAME = "CamelGtaskQueueName";
046
047 /**
048 * Camel header name corresponding to <code>X-AppEngine-TaskName</code>
049 * header created by task queueing service.
050 */
051 public static final String GTASK_TASK_NAME = "CamelGtaskTaskName";
052
053 /**
054 * Camel header name corresponding to <code>X-AppEngine-TaskRetryCount</code>
055 * header created by task queueing service.
056 */
057 public static final String GTASK_RETRY_COUNT = "CamelGtaskRetryCount";
058
059 static final String GAE_QUEUE_NAME = "X-AppEngine-QueueName";
060 static final String GAE_TASK_NAME = "X-AppEngine-TaskName";
061 static final String GAE_RETRY_COUNT = "X-AppEngine-TaskRetryCount";
062
063 // ----------------------------------------------------------------
064 // Outbound binding
065 // ----------------------------------------------------------------
066
067 /**
068 * Reads data from <code>exchange</code> and writes it to a newly created
069 * {@link TaskOptions} instance. The <code>request</code> parameter is
070 * ignored.
071 *
072 * @param endpoint
073 * @param exchange
074 * @param request
075 * ignored.
076 * @return a newly created {@link TaskOptions} instance containing data from
077 * <code>exchange</code>.
078 */
079 public TaskOptions writeRequest(GTaskEndpoint endpoint, Exchange exchange, TaskOptions request) {
080 TaskOptions answer = TaskOptions.Builder.url(getWorkerRoot(endpoint) + endpoint.getPath());
081 writeRequestHeaders(endpoint, exchange, answer);
082 writeRequestBody(endpoint, exchange, answer);
083 // TODO: consider TaskOptions method (POST, GET, ...)
084 return answer;
085 }
086
087 /**
088 * @throws UnsupportedOperationException.
089 */
090 public Exchange readResponse(GTaskEndpoint endpoint, Exchange exchange, Void response) {
091 throw new UnsupportedOperationException("gtask responses not supported");
092 }
093
094 // ----------------------------------------------------------------
095 // Inbound binding
096 // ----------------------------------------------------------------
097
098 /**
099 * Replaces the task service-specific headers (<code>X-AppEngine-*</code>)
100 * with Camel-specific headers.
101 *
102 * @see GTaskBinding#GTASK_QUEUE_NAME
103 * @see GTaskBinding#GTASK_TASK_NAME
104 * @see GTaskBinding#GTASK_RETRY_COUNT
105 * @see DefaultHttpBinding#readRequest(HttpServletRequest, HttpMessage)
106 */
107 public Exchange readRequest(GTaskEndpoint endpoint, Exchange exchange, HttpServletRequest request) {
108 readRequestHeaders(endpoint, exchange, request);
109 return exchange;
110 }
111
112 /**
113 * @throws UnsupportedOperationException.
114 */
115 public HttpServletResponse writeResponse(GTaskEndpoint endpoint, Exchange exchange, HttpServletResponse response) {
116 throw new UnsupportedOperationException("gtask responses not supported");
117 }
118
119 // ----------------------------------------------------------------
120 // Customization points
121 // ----------------------------------------------------------------
122
123 protected void writeRequestHeaders(GTaskEndpoint endpoint, Exchange exchange, TaskOptions request) {
124 HeaderFilterStrategy strategy = endpoint.getHeaderFilterStrategy();
125 for (String headerName : exchange.getIn().getHeaders().keySet()) {
126 String headerValue = exchange.getIn().getHeader(headerName, String.class);
127 if (strategy != null && !strategy.applyFilterToCamelHeaders(headerName, headerValue, exchange)) {
128 request.header(headerName, headerValue);
129 }
130 }
131 }
132
133 protected void readRequestHeaders(GTaskEndpoint endpoint, Exchange exchange, HttpServletRequest request) {
134 Message message = exchange.getIn();
135 String key = GAE_QUEUE_NAME;
136 Object val = message.getHeader(key);
137 if (val != null) {
138 message.getHeaders().put(GTASK_QUEUE_NAME, val);
139 message.getHeaders().remove(key);
140 }
141 key = GAE_TASK_NAME;
142 val = message.getHeader(key);
143 if (val != null) {
144 message.getHeaders().put(GTASK_TASK_NAME, val);
145 message.getHeaders().remove(key);
146 }
147 key = GAE_RETRY_COUNT;
148 val = message.getHeader(key);
149 if (val != null) {
150 message.getHeaders().put(GTASK_RETRY_COUNT, Integer.parseInt(val.toString()));
151 message.getHeaders().remove(key);
152 }
153 // EXPERIMENTAL // TODO: resolve gzip encoding issues
154 exchange.getIn().removeHeader("Accept-Encoding");
155 exchange.getIn().removeHeader("Content-Encoding");
156 }
157
158 protected void writeRequestBody(GTaskEndpoint endpoint, Exchange exchange, TaskOptions request) {
159 // TODO: allow message header or endpoint uri to configure character encoding and content type
160 request.payload(exchange.getIn().getBody(byte[].class), "application/octet-stream");
161 }
162
163 protected String getWorkerRoot(GTaskEndpoint endpoint) {
164 return "/" + endpoint.getWorkerRoot();
165 }
166
167 }