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            // set the endpoint uri with httpUri as we need to create http producer here
070            super(httpUri.toString(), component, httpUri, params, httpConnectionManager, clientConfigurer);
071            urlFetchService = URLFetchServiceFactory.getURLFetchService();
072        }
073    
074        /**
075         * Constructs a {@link URL} from an <code>uri</code> and an optional
076         * <code>query</code> string. The encoding strategy follow those of the
077         * Camel HTTP component.
078         * 
079         * @param uri
080         *            must be encoded with
081         *            {@link UnsafeUriCharactersEncoder#encode(String)}.
082         * @param query
083         *            decoded query string. Replaces the query part of
084         *            <code>uri</code> if not <code>null</code>.
085         */
086        @SuppressWarnings("unchecked")
087        static URL getEndpointUrl(String uri, String query) throws Exception {
088            Map<String, Object> parameters = null;
089            URI uriObj = new URI(uri);
090            if (query == null) {
091                parameters = URISupport.parseParameters(uriObj);
092            } else {
093                parameters = URISupport.parseQuery(query);
094            }
095            if (uriObj.getScheme().equals(GHTTPS_SCHEME)) {
096                uriObj = new URI(HTTPS_SCHEME + ":" + uriObj.getRawSchemeSpecificPart());
097            } else { // ghttp or anything else
098                uriObj = new URI(HTTP_SCHEME + ":" + uriObj.getRawSchemeSpecificPart());
099            }
100            return URISupport.createRemainingURI(uriObj, (Map)parameters).toURL();
101        }
102        
103        public URL getEndpointUrl() throws Exception {
104            return getEndpointUrl(getEndpointUri(), null);
105        }
106        
107        public URLFetchService getUrlFetchService() {
108            return urlFetchService;
109        }
110    
111        public void setUrlFetchService(URLFetchService urlFetchService) {
112            this.urlFetchService = urlFetchService;
113        }
114    
115        public OutboundBinding<GHttpEndpoint, HTTPRequest, HTTPResponse> getOutboundBinding() {
116            return outboundBinding;
117        }
118        
119        public void setOutboundBinding(OutboundBinding<GHttpEndpoint, HTTPRequest, HTTPResponse> outboundBinding) {
120            this.outboundBinding = outboundBinding;
121        }
122        
123        public InboundBinding<GHttpEndpoint, HttpServletRequest, HttpServletResponse> getInboundBinding() {
124            return inboundBinding;
125        }
126    
127        public void setInboundBinding(
128                InboundBinding<GHttpEndpoint, HttpServletRequest, HttpServletResponse> inboundBinding) {
129            this.inboundBinding = inboundBinding;
130        }
131    
132        /**
133         * Proxies the {@link HttpBinding} returned by {@link super#getBinding()}
134         * with a dynamic proxy. The proxy's invocation handler further delegates to
135         * {@link InboundBinding#readRequest(org.apache.camel.Endpoint, Exchange, Object)}
136         * .
137         * 
138         * @return proxied {@link HttpBinding}.
139         */
140        @Override
141        public HttpBinding getBinding() {
142            return (HttpBinding)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {HttpBinding.class}, 
143                    new HttpBindingInvocationHandler<GHttpEndpoint, HttpServletRequest, HttpServletResponse>(
144                            this, super.getBinding(), getInboundBinding()));
145        }
146    
147        public Producer createProducer() throws Exception {
148            return new GHttpProducer(this);
149        }
150    
151        @Override
152        public boolean isLenientProperties() {
153            // GHttpEndpoint could not know about all it's options on the passed URI
154            return true;
155        }
156    
157    }