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.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.withUrl(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 public HttpServletResponse writeResponse(GTaskEndpoint endpoint, Exchange exchange, HttpServletResponse response) {
113 return response;
114 }
115
116 // ----------------------------------------------------------------
117 // Customization points
118 // ----------------------------------------------------------------
119
120 protected void writeRequestHeaders(GTaskEndpoint endpoint, Exchange exchange, TaskOptions request) {
121 HeaderFilterStrategy strategy = endpoint.getHeaderFilterStrategy();
122 for (String headerName : exchange.getIn().getHeaders().keySet()) {
123 String headerValue = exchange.getIn().getHeader(headerName, String.class);
124 if (strategy != null && !strategy.applyFilterToCamelHeaders(headerName, headerValue, exchange)) {
125 request.header(headerName, headerValue);
126 }
127 }
128 }
129
130 protected void readRequestHeaders(GTaskEndpoint endpoint, Exchange exchange, HttpServletRequest request) {
131 Message message = exchange.getIn();
132 String key = GAE_QUEUE_NAME;
133 Object val = message.getHeader(key);
134 if (val != null) {
135 message.getHeaders().put(GTASK_QUEUE_NAME, val);
136 message.getHeaders().remove(key);
137 }
138 key = GAE_TASK_NAME;
139 val = message.getHeader(key);
140 if (val != null) {
141 message.getHeaders().put(GTASK_TASK_NAME, val);
142 message.getHeaders().remove(key);
143 }
144 key = GAE_RETRY_COUNT;
145 val = message.getHeader(key);
146 if (val != null) {
147 message.getHeaders().put(GTASK_RETRY_COUNT, Integer.parseInt(val.toString()));
148 message.getHeaders().remove(key);
149 }
150 // EXPERIMENTAL // TODO: resolve gzip encoding issues
151 exchange.getIn().removeHeader("Accept-Encoding");
152 exchange.getIn().removeHeader("Content-Encoding");
153 }
154
155 protected void writeRequestBody(GTaskEndpoint endpoint, Exchange exchange, TaskOptions request) {
156 // TODO: allow message header or endpoint uri to configure character encoding and content type
157 request.payload(exchange.getIn().getBody(byte[].class), "application/octet-stream");
158 }
159
160 protected String getWorkerRoot(GTaskEndpoint endpoint) {
161 return "/" + endpoint.getWorkerRoot();
162 }
163
164 }