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.http;
018    
019    import java.lang.reflect.Proxy;
020    import java.net.URI;
021    import java.net.URISyntaxException;
022    import java.net.URL;
023    import java.util.Map;
024    
025    import javax.servlet.http.HttpServletRequest;
026    import javax.servlet.http.HttpServletResponse;
027    
028    import com.google.appengine.api.urlfetch.HTTPRequest;
029    import com.google.appengine.api.urlfetch.HTTPResponse;
030    import com.google.appengine.api.urlfetch.URLFetchService;
031    
032    import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
033    import org.apache.camel.Exchange;
034    import org.apache.camel.Producer;
035    import org.apache.camel.component.gae.bind.HttpBindingInvocationHandler;
036    import org.apache.camel.component.gae.bind.InboundBinding;
037    import org.apache.camel.component.gae.bind.OutboundBinding;
038    import org.apache.camel.component.gae.bind.OutboundBindingSupport;
039    import org.apache.camel.component.http.HttpBinding;
040    import org.apache.camel.component.http.HttpClientConfigurer;
041    import org.apache.camel.component.servlet.ServletComponent;
042    import org.apache.camel.component.servlet.ServletEndpoint;
043    import org.apache.camel.util.URISupport;
044    import org.apache.camel.util.UnsafeUriCharactersEncoder;
045    import org.apache.commons.httpclient.HttpConnectionManager;
046    import org.apache.commons.httpclient.params.HttpClientParams;
047    
048    /**
049     * Represents a <a href="http://camel.apache.org/ghttp.html">Google App Engine
050     * HTTP endpoint</a>.
051     */
052    public class GHttpEndpoint extends ServletEndpoint implements OutboundBindingSupport<GHttpEndpoint, HTTPRequest, HTTPResponse> {
053    
054        public static final String GHTTP_SCHEME = "ghttp";
055        public static final String GHTTPS_SCHEME = "ghttps";
056        
057        public static final String HTTP_SCHEME = "http";
058        public static final String HTTPS_SCHEME = "https";
059        
060        private URLFetchService urlFetchService;
061        
062        private OutboundBinding<GHttpEndpoint, HTTPRequest, HTTPResponse> outboundBinding;
063        private InboundBinding<GHttpEndpoint, HttpServletRequest, HttpServletResponse> inboundBinding;
064        
065        public GHttpEndpoint(String endpointUri, ServletComponent component,
066                URI httpUri, HttpClientParams params,
067                HttpConnectionManager httpConnectionManager,
068                HttpClientConfigurer clientConfigurer) throws URISyntaxException {
069            super(endpointUri, component, httpUri, params, httpConnectionManager, clientConfigurer);
070            urlFetchService = URLFetchServiceFactory.getURLFetchService();
071        }
072    
073        /**
074         * Constructs a {@link URL} from an <code>uri</code> and an optional
075         * <code>query</code> string. The encoding strategy follow those of the
076         * Camel HTTP component.
077         * 
078         * @param uri
079         *            must be encoded with
080         *            {@link UnsafeUriCharactersEncoder#encode(String)}.
081         * @param query
082         *            decoded query string. Replaces the query part of
083         *            <code>uri</code> if not <code>null</code>.
084         */
085        @SuppressWarnings("unchecked")
086        static URL getEndpointUrl(String uri, String query) throws Exception {
087            Map<String, Object> parameters = null;
088            URI uriObj = new URI(uri);
089            if (query == null) {
090                parameters = URISupport.parseParameters(uriObj);
091            } else {
092                parameters = URISupport.parseQuery(query);
093            }
094            if (uriObj.getScheme().equals(GHTTPS_SCHEME)) {
095                uriObj = new URI(HTTPS_SCHEME + ":" + uriObj.getRawSchemeSpecificPart());
096            } else { // ghttp or anything else
097                uriObj = new URI(HTTP_SCHEME + ":" + uriObj.getRawSchemeSpecificPart());
098            }
099            return URISupport.createRemainingURI(uriObj, (Map)parameters).toURL();
100        }
101        
102        public URL getEndpointUrl() throws Exception {
103            return getEndpointUrl(getEndpointUri(), null);
104        }
105        
106        public URLFetchService getUrlFetchService() {
107            return urlFetchService;
108        }
109    
110        public void setUrlFetchService(URLFetchService urlFetchService) {
111            this.urlFetchService = urlFetchService;
112        }
113    
114        public OutboundBinding<GHttpEndpoint, HTTPRequest, HTTPResponse> getOutboundBinding() {
115            return outboundBinding;
116        }
117        
118        public void setOutboundBinding(OutboundBinding<GHttpEndpoint, HTTPRequest, HTTPResponse> outboundBinding) {
119            this.outboundBinding = outboundBinding;
120        }
121        
122        public InboundBinding<GHttpEndpoint, HttpServletRequest, HttpServletResponse> getInboundBinding() {
123            return inboundBinding;
124        }
125    
126        public void setInboundBinding(
127                InboundBinding<GHttpEndpoint, HttpServletRequest, HttpServletResponse> inboundBinding) {
128            this.inboundBinding = inboundBinding;
129        }
130    
131        /**
132         * Proxies the {@link HttpBinding} returned by {@link super#getBinding()}
133         * with a dynamic proxy. The proxy's invocation handler further delegates to
134         * {@link InboundBinding#readRequest(org.apache.camel.Endpoint, Exchange, Object)}
135         * .
136         * 
137         * @return proxied {@link HttpBinding}.
138         */
139        @Override
140        public HttpBinding getBinding() {
141            return (HttpBinding)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {HttpBinding.class}, 
142                    new HttpBindingInvocationHandler<GHttpEndpoint, HttpServletRequest, HttpServletResponse>(
143                            this, super.getBinding(), getInboundBinding()));
144        }
145    
146        public Producer createProducer() throws Exception {
147            return new GHttpProducer(this);
148        }
149    
150    }