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 }