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.servicemix.http;
018    
019    import java.net.URI;
020    import java.util.List;
021    import java.util.Map;
022    
023    import javax.jbi.messaging.MessageExchange;
024    import javax.jbi.servicedesc.ServiceEndpoint;
025    
026    import org.apache.commons.httpclient.HttpClient;
027    import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
028    import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
029    import org.apache.servicemix.common.BaseServiceUnitManager;
030    import org.apache.servicemix.common.DefaultComponent;
031    import org.apache.servicemix.common.Deployer;
032    import org.apache.servicemix.common.Endpoint;
033    import org.apache.servicemix.common.ServiceUnit;
034    import org.apache.servicemix.common.DefaultServiceUnit;
035    import org.apache.servicemix.common.util.IntrospectionSupport;
036    import org.apache.servicemix.common.util.URISupport;
037    import org.apache.servicemix.common.security.AuthenticationService;
038    import org.apache.servicemix.common.security.KeystoreManager;
039    import org.apache.servicemix.common.xbean.BaseXBeanDeployer;
040    import org.apache.servicemix.http.endpoints.HttpConsumerEndpoint;
041    import org.apache.servicemix.http.endpoints.HttpProviderEndpoint;
042    import org.apache.servicemix.http.jetty.JCLLogger;
043    import org.apache.servicemix.http.jetty.JettyContextManager;
044    import org.mortbay.thread.QueuedThreadPool;
045    
046    /**
047     * an HTTP JBI component
048     * 
049     * @author gnodet
050     * @org.apache.xbean.XBean element="component"
051     *                         description="an HTTP JBI component. The component is responsible for hosting HTTP endpoints."
052     */
053    public class HttpComponent extends DefaultComponent {
054    
055        public static final String[] EPR_PROTOCOLS = {"http:", "https"};
056    
057        static {
058            JCLLogger.init();
059        }
060    
061        protected ContextManager server;
062        protected HttpClient client;
063        protected MultiThreadedHttpConnectionManager connectionManager;
064        protected org.mortbay.jetty.client.HttpClient connectionPool;
065        protected HttpConfiguration configuration = new HttpConfiguration();
066        protected HttpEndpointType[] endpoints;
067    
068        protected String protocol;
069        protected String host;
070        protected int port = 80;
071        protected String path;
072    
073        /**
074         * Returns the host name.
075         * 
076         * @return a string contianing the host name
077         */
078        public String getHost() {
079            return host;
080        }
081    
082        /**
083         * Sets the host name.
084         * 
085         * @param host a string specifying the host name
086         * @org.apache.xbean.Property description="the host name"
087         */
088        public void setHost(String host) {
089            this.host = host;
090        }
091    
092        /**
093         * @return the path
094         */
095        public String getPath() {
096            return path;
097        }
098    
099        /**
100         * @param path the path to set
101         */
102        public void setPath(String path) {
103            this.path = path;
104        }
105    
106        /**
107         * @return the port
108         */
109        public int getPort() {
110            return port;
111        }
112    
113        /**
114         * @param port the port to set
115         * @org.apache.xbean.Property description="the port number. The default is 80."
116         */
117        public void setPort(int port) {
118            this.port = port;
119        }
120    
121        /**
122         * @return the protocol
123         */
124        public String getProtocol() {
125            return protocol;
126        }
127    
128        /**
129         * @param protocol the protocol to set
130         * @org.apache.xbean.Property description="the protocol being used. Valid values are <code>http:</code> and <code>https:</code>"
131         */
132        public void setProtocol(String protocol) {
133            this.protocol = protocol;
134        }
135    
136        /**
137         * @return the endpoints
138         */
139        public HttpEndpointType[] getEndpoints() {
140            return endpoints;
141        }
142    
143        /**
144         * @param endpoints the endpoints to set
145         * @org.apache.xbean.Property description="the endpoints hosted by a component"
146         */
147        public void setEndpoints(HttpEndpointType[] endpoints) {
148            this.endpoints = endpoints;
149        }
150    
151        public ContextManager getServer() {
152            return server;
153        }
154    
155        public void setServer(ContextManager server) {
156            this.server = server;
157        }
158    
159        public HttpClient getClient() {
160            return client;
161        }
162    
163        /**
164         * @param client the HTTP client instance used by the component
165         * @org.apache.xbean.Property description="the Apache Commons HTTP client used by a component"
166         */
167        public void setClient(HttpClient client) {
168            this.client = client;
169        }
170    
171        public org.mortbay.jetty.client.HttpClient getConnectionPool() {
172            return connectionPool;
173        }
174    
175        public org.mortbay.jetty.client.HttpClient createNewJettyClient() throws Exception {
176            org.mortbay.jetty.client.HttpClient tempClient = new org.mortbay.jetty.client.HttpClient();
177            QueuedThreadPool btp = new QueuedThreadPool();
178            btp.setMaxThreads(getConfiguration().getJettyClientThreadPoolSize());
179            tempClient.setThreadPool(btp);
180            tempClient.setConnectorType(org.mortbay.jetty.client.HttpClient.CONNECTOR_SELECT_CHANNEL);
181            tempClient.start();
182            return tempClient;
183        }
184    
185        /**
186         * Sets the connection pool used by the component. The connection pool is a Jetty HTTP client instance with a thread pool set
187         * using the HTTP component's <code>jettyClientThreadPoolSize</code> property.
188         * 
189         * @param connectionPool a Jetty <code>HttpClient</code>
190         * @org.apache.xbean.Property description="a Jetty HTTP client instance maintaining a thread pool for client-side connections"
191         */
192        public void setConnectionPool(org.mortbay.jetty.client.HttpClient connectionPool) {
193            this.connectionPool = connectionPool;
194        }
195    
196        /**
197         * @return Returns the configuration.
198         * @org.apache.xbean.Flat
199         */
200        public HttpConfiguration getConfiguration() {
201            return configuration;
202        }
203    
204        /**
205         * @param configuration an <code>HttpConfiguration</code> object containing the configuration information needed to establish
206         *            HTTP connections
207         * @org.apache.xbean.Property description="the HTTP configuration information used to establish HTTP connections"
208         */
209        public void setConfiguration(HttpConfiguration configuration) {
210            this.configuration = configuration;
211        }
212    
213        /*
214         * (non-Javadoc)
215         * @see org.servicemix.common.BaseComponentLifeCycle#getExtensionMBean()
216         */
217        protected Object getExtensionMBean() throws Exception {
218            return configuration;
219        }
220    
221        protected void doInit() throws Exception {
222            // Load configuration
223            configuration.setRootDir(context.getWorkspaceRoot());
224            configuration.setComponentName(context.getComponentName());
225            configuration.load();
226            // Lookup keystoreManager and authenticationService
227            if (configuration.getKeystoreManager() == null) {
228                try {
229                    String name = configuration.getKeystoreManagerName();
230                    Object km = context.getNamingContext().lookup(name);
231                    configuration.setKeystoreManager(km);
232                } catch (Throwable e) {
233                    // ignore
234                }
235            }
236            if (configuration.getAuthenticationService() == null) {
237                try {
238                    String name = configuration.getAuthenticationServiceName();
239                    Object as = context.getNamingContext().lookup(name);
240                    configuration.setAuthenticationService(as);
241                } catch (Throwable e) {
242                    try {
243                        Class cl = Class
244                            .forName("org.apache.servicemix.jbi.security.auth.impl.JAASAuthenticationService");
245                        configuration.setAuthenticationService(cl.newInstance());
246                    } catch (Throwable t) {
247                        logger.warn("Unable to retrieve or create the authentication service");
248                    }
249                }
250            }
251            // Create client
252            if (client == null) {
253                connectionManager = new MultiThreadedHttpConnectionManager();
254                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
255                params.setDefaultMaxConnectionsPerHost(configuration.getMaxConnectionsPerHost());
256                params.setMaxTotalConnections(configuration.getMaxTotalConnections());
257                connectionManager.setParams(params);
258                client = new HttpClient(connectionManager);
259            }
260            // Create connectionPool
261            if (connectionPool == null) {
262                connectionPool = createNewJettyClient();
263            }
264            // Create serverManager
265            if (configuration.isManaged()) {
266                server = new ManagedContextManager();
267            } else {
268                JettyContextManager jcm = new JettyContextManager();
269                jcm.setMBeanServer(context.getMBeanServer());
270                this.server = jcm;
271            }
272            server.setConfiguration(configuration);
273            server.init();
274            server.start();
275            // Default initalization
276            super.doInit();
277        }
278    
279        protected void doShutDown() throws Exception {
280            super.doShutDown();
281            if (server != null) {
282                ContextManager s = server;
283                server = null;
284                s.stop();
285                s.shutDown();
286            }
287            if (connectionPool != null) {
288                connectionPool.stop();
289                connectionPool = null;
290            }
291            if (connectionManager != null) {
292                connectionManager.shutdown();
293                connectionManager = null;
294                client = null;
295            }
296        }
297    
298        protected void doStart() throws Exception {
299            super.doStart();
300        }
301    
302        protected void doStop() throws Exception {
303            super.doStop();
304        }
305    
306        protected String[] getEPRProtocols() {
307            return EPR_PROTOCOLS;
308        }
309    
310        protected Endpoint getResolvedEPR(ServiceEndpoint ep) throws Exception {
311            // We receive an exchange for an EPR that has not been used yet.
312            // Register a provider endpoint and restart processing.
313            HttpEndpoint httpEp = new HttpEndpoint(true);
314            httpEp.setServiceUnit(new DefaultServiceUnit(component));
315            httpEp.setService(ep.getServiceName());
316            httpEp.setEndpoint(ep.getEndpointName());
317            httpEp.setRole(MessageExchange.Role.PROVIDER);
318            URI uri = new URI(ep.getEndpointName());
319            Map map = URISupport.parseQuery(uri.getQuery());
320            if (IntrospectionSupport.setProperties(httpEp, map, "http.")) {
321                uri = URISupport.createRemainingURI(uri, map);
322            }
323            if (httpEp.getLocationURI() == null) {
324                httpEp.setLocationURI(uri.toString());
325            }
326            return httpEp;
327        }
328    
329        /**
330         * @return the keystoreManager
331         */
332        public Object getKeystoreManager() {
333            return configuration.getKeystoreManager();
334        }
335    
336        /**
337         * @param keystoreManager the keystoreManager to set
338         * @org.apache.xbean.Property description="the keystore manager object used by a component"
339         */
340        public void setKeystoreManager(Object keystoreManager) {
341            this.configuration.setKeystoreManager(keystoreManager);
342        }
343    
344        /**
345         * @return the authenticationService
346         */
347        public Object getAuthenticationService() {
348            return configuration.getAuthenticationService();
349        }
350    
351        /**
352         * @param authenticationService the authenticationService to set
353         * @org.apache.xbean.Property description="the authentication service object used by a component"
354         */
355        public void setAuthenticationService(Object authenticationService) {
356            this.configuration.setAuthenticationService(authenticationService);
357        }
358    
359        /**
360         * When servicemix-http is embedded inside a web application and configured to reuse the existing servlet container, this method
361         * will create and return the HTTPProcessor which will handle all servlet calls
362         */
363        public HttpProcessor getMainProcessor() {
364            return server.getMainProcessor();
365        }
366    
367        /*
368         * (non-Javadoc)
369         * @see org.servicemix.common.BaseComponent#createServiceUnitManager()
370         */
371        public BaseServiceUnitManager createServiceUnitManager() {
372            Deployer[] deployers = new Deployer[] {new BaseXBeanDeployer(this, getEndpointClasses()),
373                                                   new HttpWsdl1Deployer(this)};
374            return new BaseServiceUnitManager(this, deployers);
375        }
376    
377        protected List getConfiguredEndpoints() {
378            return asList(endpoints);
379        }
380    
381        protected Class[] getEndpointClasses() {
382            return new Class[] {HttpEndpoint.class, HttpConsumerEndpoint.class, HttpProviderEndpoint.class};
383        }
384    
385    }