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.jetty;
018
019 import java.io.File;
020 import java.net.URI;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024
025 import javax.management.MBeanServer;
026
027 import org.apache.camel.CamelContext;
028 import org.apache.camel.Endpoint;
029 import org.apache.camel.RuntimeCamelException;
030 import org.apache.camel.component.http.CamelServlet;
031 import org.apache.camel.component.http.HttpBinding;
032 import org.apache.camel.component.http.HttpComponent;
033 import org.apache.camel.component.http.HttpConsumer;
034 import org.apache.camel.component.http.HttpEndpoint;
035 import org.apache.camel.spi.ManagementAgent;
036 import org.apache.camel.spi.ManagementStrategy;
037 import org.apache.camel.util.CastUtils;
038 import org.apache.camel.util.IntrospectionSupport;
039 import org.apache.camel.util.ObjectHelper;
040 import org.apache.camel.util.URISupport;
041 import org.apache.commons.logging.Log;
042 import org.apache.commons.logging.LogFactory;
043 import org.eclipse.jetty.client.Address;
044 import org.eclipse.jetty.client.HttpClient;
045 import org.eclipse.jetty.jmx.MBeanContainer;
046 import org.eclipse.jetty.server.Connector;
047 import org.eclipse.jetty.server.Handler;
048 import org.eclipse.jetty.server.Server;
049 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
050 import org.eclipse.jetty.server.handler.HandlerCollection;
051 import org.eclipse.jetty.server.handler.HandlerWrapper;
052 import org.eclipse.jetty.server.nio.SelectChannelConnector;
053 import org.eclipse.jetty.server.session.SessionHandler;
054 import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
055 import org.eclipse.jetty.servlet.FilterHolder;
056 import org.eclipse.jetty.servlet.ServletContextHandler;
057 import org.eclipse.jetty.servlet.ServletHolder;
058 import org.eclipse.jetty.util.component.LifeCycle;
059 import org.eclipse.jetty.util.thread.QueuedThreadPool;
060 import org.eclipse.jetty.util.thread.ThreadPool;
061
062 /**
063 * An HttpComponent which starts an embedded Jetty for to handle consuming from
064 * the http endpoints.
065 *
066 * @version $Revision: 989477 $
067 */
068 public class JettyHttpComponent extends HttpComponent {
069 public static final String TMP_DIR = "CamelJettyTempDir";
070
071 protected static final HashMap<String, ConnectorRef> CONNECTORS = new HashMap<String, ConnectorRef>();
072
073 private static final transient Log LOG = LogFactory.getLog(JettyHttpComponent.class);
074 private static final String JETTY_SSL_KEYSTORE = "org.eclipse.jetty.ssl.keystore";
075 private static final String JETTY_SSL_KEYPASSWORD = "org.eclipse.jetty.ssl.keypassword";
076 private static final String JETTY_SSL_PASSWORD = "org.eclipse.jetty.ssl.password";
077
078 protected String sslKeyPassword;
079 protected String sslPassword;
080 protected String sslKeystore;
081 protected Map<Integer, SslSelectChannelConnector> sslSocketConnectors;
082 protected Map<Integer, SelectChannelConnector> socketConnectors;
083 protected Map<String, Object> sslSocketConnectorProperties;
084 protected Map<String, Object> socketConnectorProperties;
085 protected HttpClient httpClient;
086 protected ThreadPool httpClientThreadPool;
087 protected Integer httpClientMinThreads;
088 protected Integer httpClientMaxThreads;
089 protected Integer minThreads;
090 protected Integer maxThreads;
091 protected ThreadPool threadPool;
092 protected MBeanContainer mbContainer;
093 protected boolean enableJmx;
094
095 class ConnectorRef {
096 Server server;
097 Connector connector;
098 CamelServlet servlet;
099 int refCount;
100
101 public ConnectorRef(Server server, Connector connector, CamelServlet servlet) {
102 this.server = server;
103 this.connector = connector;
104 this.servlet = servlet;
105 increment();
106 }
107
108 public int increment() {
109 return ++refCount;
110 }
111
112 public int decrement() {
113 return --refCount;
114 }
115
116 public int getRefCount() {
117 return refCount;
118 }
119 }
120
121 @Override
122 protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
123 String addressUri = uri.startsWith("jetty:") ? remaining : uri;
124 Map<String, Object> httpClientParameters = new HashMap<String, Object>(parameters);
125
126 // must extract well known parameters before we create the endpoint
127 List<Handler> handlerList = resolveAndRemoveReferenceListParameter(parameters, "handlers", Handler.class);
128 HttpBinding binding = resolveAndRemoveReferenceParameter(parameters, "httpBindingRef", HttpBinding.class);
129 Boolean throwExceptionOnFailure = getAndRemoveParameter(parameters, "throwExceptionOnFailure", Boolean.class);
130 Boolean bridgeEndpoint = getAndRemoveParameter(parameters, "bridgeEndpoint", Boolean.class);
131 Boolean matchOnUriPrefix = getAndRemoveParameter(parameters, "matchOnUriPrefix", Boolean.class);
132 Boolean enableJmx = getAndRemoveParameter(parameters, "enableJmx", Boolean.class);
133 Boolean enableMultipartFilter = getAndRemoveParameter(parameters, "enableMultipartFilter",
134 Boolean.class, true);
135
136 // configure http client if we have url configuration for it
137 // http client is only used for jetty http producer (hence not very commonly used)
138 HttpClient client = null;
139 if (IntrospectionSupport.hasProperties(parameters, "httpClient.")) {
140 // set additional parameters on http client
141 // only create client when needed
142 client = getHttpClient();
143 IntrospectionSupport.setProperties(client, parameters, "httpClient.");
144 // validate that we could resolve all httpClient. parameters as this component is lenient
145 validateParameters(uri, parameters, "httpClient.");
146 }
147 // keep the configure parameters for the http client
148 for (String key : parameters.keySet()) {
149 httpClientParameters.remove(key);
150 }
151 URI endpointUri = URISupport.createRemainingURI(new URI(addressUri), CastUtils.cast(httpClientParameters));
152
153 // restructure uri to be based on the parameters left as we dont want to include the Camel internal options
154 URI httpUri = URISupport.createRemainingURI(new URI(addressUri), CastUtils.cast(parameters));
155
156 // create endpoint after all known parameters have been extracted from parameters
157 JettyHttpEndpoint endpoint = new JettyHttpEndpoint(this, endpointUri.toString(), httpUri);
158 setEndpointHeaderFilterStrategy(endpoint);
159
160 if (client != null) {
161 endpoint.setClient(client);
162 }
163 if (handlerList.size() > 0) {
164 endpoint.setHandlers(handlerList);
165 }
166 // prefer to use endpoint configured over component configured
167 if (binding == null) {
168 // fallback to component configured
169 binding = getHttpBinding();
170 }
171 if (binding != null) {
172 endpoint.setBinding(binding);
173 }
174 // should we use an exception for failed error codes?
175 if (throwExceptionOnFailure != null) {
176 endpoint.setThrowExceptionOnFailure(throwExceptionOnFailure);
177 }
178 if (bridgeEndpoint != null) {
179 endpoint.setBridgeEndpoint(bridgeEndpoint);
180 }
181 if (matchOnUriPrefix != null) {
182 endpoint.setMatchOnUriPrefix(matchOnUriPrefix);
183 }
184
185 if (enableJmx != null) {
186 endpoint.setEnableJmx(enableJmx);
187 } else {
188 // set this option based on setting of JettyHttpComponent
189 endpoint.setEnableJmx(isEnableJmx());
190 }
191
192 endpoint.setEnableMultipartFilter(enableMultipartFilter);
193
194 setProperties(endpoint, parameters);
195 return endpoint;
196 }
197
198 /**
199 * Connects the URL specified on the endpoint to the specified processor.
200 */
201 @Override
202 public void connect(HttpConsumer consumer) throws Exception {
203 // Make sure that there is a connector for the requested endpoint.
204 JettyHttpEndpoint endpoint = (JettyHttpEndpoint)consumer.getEndpoint();
205 String connectorKey = getConnectorKey(endpoint);
206
207 synchronized (CONNECTORS) {
208 ConnectorRef connectorRef = CONNECTORS.get(connectorKey);
209 if (connectorRef == null) {
210 Connector connector;
211 if ("https".equals(endpoint.getProtocol())) {
212 connector = getSslSocketConnector(endpoint.getPort());
213 } else {
214 connector = getSocketConnector(endpoint.getPort());
215 }
216 connector.setPort(endpoint.getPort());
217 connector.setHost(endpoint.getHttpUri().getHost());
218 if ("localhost".equalsIgnoreCase(endpoint.getHttpUri().getHost())) {
219 LOG.warn("You use localhost interface! It means that no external connections will be available."
220 + " Don't you want to use 0.0.0.0 instead (all network interfaces)? " + endpoint);
221 }
222 Server server = createServer();
223 if (endpoint.isEnableJmx()) {
224 enableJmx(server);
225 }
226 server.addConnector(connector);
227
228 connectorRef = new ConnectorRef(server, connector, createServletForConnector(server, connector, endpoint.getHandlers()));
229 // must enable session before we start
230 if (endpoint.isSessionSupport()) {
231 enableSessionSupport(connectorRef.server, connectorKey);
232 }
233 connectorRef.server.start();
234
235 CONNECTORS.put(connectorKey, connectorRef);
236
237 } else {
238 // ref track the connector
239 connectorRef.increment();
240 }
241 // check the session support
242 if (endpoint.isSessionSupport()) {
243 enableSessionSupport(connectorRef.server, connectorKey);
244 }
245
246 if (endpoint.isEnableMultipartFilter()) {
247 enableMultipartFilter(endpoint, connectorRef.server, connectorKey);
248 }
249 connectorRef.servlet.connect(consumer);
250 }
251 }
252
253 private void enableJmx(Server server) {
254 MBeanContainer containerToRegister = getMbContainer();
255 if (containerToRegister != null) {
256 LOG.info("Jetty JMX Extensions is enabled");
257 server.getContainer().addEventListener(containerToRegister);
258 // Since we may have many Servers running, don't tie the MBeanContainer
259 // to a Server lifecycle or we end up closing it while it is still in use.
260 //server.addBean(mbContainer);
261 }
262 }
263
264 private void enableSessionSupport(Server server, String connectorKey) throws Exception {
265 ServletContextHandler context = (ServletContextHandler)server.getChildHandlerByClass(ServletContextHandler.class);
266 if (context.getSessionHandler() == null) {
267 SessionHandler sessionHandler = new SessionHandler();
268 if (context.isStarted()) {
269 throw new IllegalStateException("Server has already been started. Cannot enabled sessionSupport on " + connectorKey);
270 } else {
271 context.setSessionHandler(sessionHandler);
272 }
273 }
274 }
275
276 private void enableMultipartFilter(HttpEndpoint endpoint, Server server, String connectorKey) throws Exception {
277 ServletContextHandler context = (ServletContextHandler) server
278 .getChildHandlerByClass(ServletContextHandler.class);
279 CamelContext camelContext = this.getCamelContext();
280 FilterHolder filterHolder = new FilterHolder();
281 filterHolder.setInitParameter("deleteFiles", "true");
282 if (ObjectHelper.isNotEmpty(camelContext.getProperties().get(TMP_DIR))) {
283 File file = new File(camelContext.getProperties().get(TMP_DIR));
284 if (!file.isDirectory()) {
285 throw new RuntimeCamelException(
286 "The temp file directory of camel-jetty is not exists, please recheck it with directory name :"
287 + camelContext.getProperties().get(TMP_DIR));
288 }
289 context.setAttribute("javax.servlet.context.tempdir", file);
290 }
291 filterHolder.setFilter(new CamelMultipartFilter());
292 // add the default MultiPartFilter filter for it
293 String pathSpec = endpoint.getPath();
294 if (pathSpec == null || "".equals(pathSpec)) {
295 pathSpec = "/";
296 }
297 if (endpoint.isMatchOnUriPrefix()) {
298 pathSpec = pathSpec.endsWith("/") ? pathSpec + "*" : pathSpec + "/*";
299 }
300 context.addFilter(filterHolder, pathSpec, 0);
301 }
302
303 /**
304 * Disconnects the URL specified on the endpoint from the specified processor.
305 */
306 @Override
307 public void disconnect(HttpConsumer consumer) throws Exception {
308 // If the connector is not needed anymore then stop it
309 HttpEndpoint endpoint = consumer.getEndpoint();
310 String connectorKey = getConnectorKey(endpoint);
311
312 synchronized (CONNECTORS) {
313 ConnectorRef connectorRef = CONNECTORS.get(connectorKey);
314 if (connectorRef != null) {
315 connectorRef.servlet.disconnect(consumer);
316 if (connectorRef.decrement() == 0) {
317 connectorRef.server.removeConnector(connectorRef.connector);
318 connectorRef.connector.stop();
319 connectorRef.server.stop();
320 CONNECTORS.remove(connectorKey);
321 // Camel controls the lifecycle of these entities so remove the
322 // registered MBeans when Camel is done with the managed objects.
323 if (mbContainer != null) {
324 mbContainer.removeBean(connectorRef.server);
325 mbContainer.removeBean(connectorRef.connector);
326 }
327 }
328 }
329 }
330 }
331
332 private String getConnectorKey(HttpEndpoint endpoint) {
333 return endpoint.getProtocol() + ":" + endpoint.getHttpUri().getHost() + ":" + endpoint.getPort();
334 }
335
336 // Properties
337 // -------------------------------------------------------------------------
338
339 public String getSslKeyPassword() {
340 return sslKeyPassword;
341 }
342
343 public void setSslKeyPassword(String sslKeyPassword) {
344 this.sslKeyPassword = sslKeyPassword;
345 }
346
347 public String getSslPassword() {
348 return sslPassword;
349 }
350
351 public void setSslPassword(String sslPassword) {
352 this.sslPassword = sslPassword;
353 }
354
355 public void setKeystore(String sslKeystore) {
356 this.sslKeystore = sslKeystore;
357 }
358
359 public String getKeystore() {
360 return sslKeystore;
361 }
362
363 protected SslSelectChannelConnector getSslSocketConnector(int port) throws Exception {
364 SslSelectChannelConnector answer = null;
365 if (sslSocketConnectors != null) {
366 answer = sslSocketConnectors.get(port);
367 }
368 if (answer == null) {
369 answer = createSslSocketConnector();
370 }
371 return answer;
372 }
373
374 protected SslSelectChannelConnector createSslSocketConnector() throws Exception {
375 SslSelectChannelConnector answer = new SslSelectChannelConnector();
376 // with default null values, jetty ssl system properties
377 // and console will be read by jetty implementation
378
379 String keystoreProperty = System.getProperty(JETTY_SSL_KEYSTORE);
380 if (keystoreProperty != null) {
381 answer.setKeystore(keystoreProperty);
382 } else if (sslKeystore != null) {
383 answer.setKeystore(sslKeystore);
384 }
385
386 String keystorePassword = System.getProperty(JETTY_SSL_KEYPASSWORD);
387 if (keystorePassword != null) {
388 answer.setKeyPassword(keystorePassword);
389 } else if (sslKeyPassword != null) {
390 answer.setKeyPassword(sslKeyPassword);
391 }
392
393 String password = System.getProperty(JETTY_SSL_PASSWORD);
394 if (password != null) {
395 answer.setPassword(password);
396 } else if (sslPassword != null) {
397 answer.setPassword(sslPassword);
398 }
399
400 if (getSslSocketConnectorProperties() != null) {
401 // must copy the map otherwise it will be deleted
402 Map<String, Object> properties = new HashMap<String, Object>(getSslSocketConnectorProperties());
403 IntrospectionSupport.setProperties(answer, properties);
404 if (properties.size() > 0) {
405 throw new IllegalArgumentException("There are " + properties.size()
406 + " parameters that couldn't be set on the SslSocketConnector."
407 + " Check the uri if the parameters are spelt correctly and that they are properties of the SslSocketConnector."
408 + " Unknown parameters=[" + properties + "]");
409 }
410 }
411 return answer;
412 }
413
414 public Map<Integer, SslSelectChannelConnector> getSslSocketConnectors() {
415 return sslSocketConnectors;
416 }
417
418 public void setSslSocketConnectors(Map <Integer, SslSelectChannelConnector> connectors) {
419 sslSocketConnectors = connectors;
420 }
421
422 public SelectChannelConnector getSocketConnector(int port) throws Exception {
423 SelectChannelConnector answer = null;
424 if (socketConnectors != null) {
425 answer = socketConnectors.get(port);
426 }
427 if (answer == null) {
428 answer = createSocketConnector();
429 }
430 return answer;
431 }
432
433 protected SelectChannelConnector createSocketConnector() throws Exception {
434 SelectChannelConnector answer = new SelectChannelConnector();
435 if (getSocketConnectorProperties() != null) {
436 // must copy the map otherwise it will be deleted
437 Map<String, Object> properties = new HashMap<String, Object>(getSocketConnectorProperties());
438 IntrospectionSupport.setProperties(answer, properties);
439 if (properties.size() > 0) {
440 throw new IllegalArgumentException("There are " + properties.size()
441 + " parameters that couldn't be set on the SocketConnector."
442 + " Check the uri if the parameters are spelt correctly and that they are properties of the SelectChannelConnector."
443 + " Unknown parameters=[" + properties + "]");
444 }
445 }
446 return answer;
447 }
448
449 public void setSocketConnectors(Map<Integer, SelectChannelConnector> socketConnectors) {
450 this.socketConnectors = socketConnectors;
451 }
452
453 public synchronized HttpClient getHttpClient() {
454 if (httpClient == null) {
455 httpClient = new HttpClient();
456 httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
457
458 if (System.getProperty("http.proxyHost") != null && System.getProperty("http.proxyPort") != null) {
459 String host = System.getProperty("http.proxyHost");
460 int port = Integer.parseInt(System.getProperty("http.proxyPort"));
461 if (LOG.isDebugEnabled()) {
462 LOG.debug("Java System Property http.proxyHost and http.proxyPort detected. Using http proxy host: "
463 + host + " port: " + port);
464 }
465 httpClient.setProxy(new Address(host, port));
466 }
467
468 // use QueueThreadPool as the default bounded is deprecated (see SMXCOMP-157)
469 if (getHttpClientThreadPool() == null) {
470 QueuedThreadPool qtp = new QueuedThreadPool();
471 if (httpClientMinThreads != null) {
472 qtp.setMinThreads(httpClientMinThreads.intValue());
473 }
474 if (httpClientMaxThreads != null) {
475 qtp.setMaxThreads(httpClientMaxThreads.intValue());
476 }
477 try {
478 qtp.start();
479 } catch (Exception e) {
480 throw new RuntimeCamelException("Error starting JettyHttpClient thread pool: " + qtp, e);
481 }
482 setHttpClientThreadPool(qtp);
483 }
484 httpClient.setThreadPool(getHttpClientThreadPool());
485 }
486 return httpClient;
487 }
488
489 public void setHttpClient(HttpClient httpClient) {
490 this.httpClient = httpClient;
491 }
492
493 public ThreadPool getHttpClientThreadPool() {
494 return httpClientThreadPool;
495 }
496
497 public void setHttpClientThreadPool(ThreadPool httpClientThreadPool) {
498 this.httpClientThreadPool = httpClientThreadPool;
499 }
500
501 public Integer getHttpClientMinThreads() {
502 return httpClientMinThreads;
503 }
504
505 public void setHttpClientMinThreads(Integer httpClientMinThreads) {
506 this.httpClientMinThreads = httpClientMinThreads;
507 }
508
509 public Integer getHttpClientMaxThreads() {
510 return httpClientMaxThreads;
511 }
512
513 public void setHttpClientMaxThreads(Integer httpClientMaxThreads) {
514 this.httpClientMaxThreads = httpClientMaxThreads;
515 }
516
517 public Integer getMinThreads() {
518 return minThreads;
519 }
520
521 public void setMinThreads(Integer minThreads) {
522 this.minThreads = minThreads;
523 }
524
525 public Integer getMaxThreads() {
526 return maxThreads;
527 }
528
529 public void setMaxThreads(Integer maxThreads) {
530 this.maxThreads = maxThreads;
531 }
532
533 public ThreadPool getThreadPool() {
534 return threadPool;
535 }
536
537 public void setThreadPool(ThreadPool threadPool) {
538 this.threadPool = threadPool;
539 }
540
541 public void setEnableJmx(boolean enableJmx) {
542 this.enableJmx = enableJmx;
543 }
544
545 public boolean isEnableJmx() {
546 return enableJmx;
547 }
548
549 public synchronized MBeanContainer getMbContainer() {
550 // If null, provide the default implementation.
551 if (mbContainer == null) {
552 MBeanServer mbs = null;
553
554 final ManagementStrategy mStrategy = this.getCamelContext().getManagementStrategy();
555 final ManagementAgent mAgent = mStrategy.getManagementAgent();
556 if (mAgent != null) {
557 mbs = mAgent.getMBeanServer();
558 }
559
560 if (mbs != null) {
561 mbContainer = new MBeanContainer(mbs);
562 startMbContainer();
563 } else {
564 LOG.warn("JMX disabled in CamelContext. Jetty JMX extensions will remain disabled.");
565 }
566 }
567
568 return this.mbContainer;
569 }
570
571 public void setMbContainer(MBeanContainer mbContainer) {
572 this.mbContainer = mbContainer;
573 }
574
575 public Map<String, Object> getSslSocketConnectorProperties() {
576 return sslSocketConnectorProperties;
577 }
578
579 public void setSslSocketConnectorProperties(Map<String, Object> sslSocketConnectorProperties) {
580 this.sslSocketConnectorProperties = sslSocketConnectorProperties;
581 }
582
583 public Map<String, Object> getSocketConnectorProperties() {
584 return socketConnectorProperties;
585 }
586
587 public void setSocketConnectorProperties(Map<String, Object> socketConnectorProperties) {
588 this.socketConnectorProperties = socketConnectorProperties;
589 }
590
591 public void addSocketConnectorProperty(String key, Object value) {
592 if (socketConnectorProperties == null) {
593 socketConnectorProperties = new HashMap<String, Object>();
594 }
595 socketConnectorProperties.put(key, value);
596 }
597
598 public void addSslSocketConnectorProperty(String key, Object value) {
599 if (sslSocketConnectorProperties == null) {
600 sslSocketConnectorProperties = new HashMap<String, Object>();
601 }
602 sslSocketConnectorProperties.put(key, value);
603 }
604
605 // Implementation methods
606 // -------------------------------------------------------------------------
607 protected CamelServlet createServletForConnector(Server server, Connector connector, List<Handler> handlers) throws Exception {
608 ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
609 context.setConnectorNames(new String[] {connector.getName()});
610
611 if (handlers != null && !handlers.isEmpty()) {
612 for (Handler handler : handlers) {
613 if (handler instanceof HandlerWrapper) {
614 ((HandlerWrapper) handler).setHandler(server.getHandler());
615 server.setHandler(handler);
616 } else {
617 HandlerCollection handlerCollection = new HandlerCollection();
618 handlerCollection.addHandler(server.getHandler());
619 handlerCollection.addHandler(handler);
620 server.setHandler(handlerCollection);
621 }
622 }
623 }
624
625 // use Jetty continuations
626 CamelServlet camelServlet = new CamelContinuationServlet();
627 ServletHolder holder = new ServletHolder();
628 holder.setServlet(camelServlet);
629 context.addServlet(holder, "/*");
630
631 return camelServlet;
632 }
633
634 protected Server createServer() throws Exception {
635 Server server = new Server();
636 ContextHandlerCollection collection = new ContextHandlerCollection();
637 server.setHandler(collection);
638
639 // configure thread pool if min/max given
640 if (minThreads != null || maxThreads != null) {
641 if (getThreadPool() != null) {
642 throw new IllegalArgumentException("You cannot configure both minThreads/maxThreads and a custom threadPool on JettyHttpComponent: " + this);
643 }
644 QueuedThreadPool qtp = new QueuedThreadPool();
645 if (minThreads != null) {
646 qtp.setMinThreads(minThreads.intValue());
647 }
648 if (maxThreads != null) {
649 qtp.setMaxThreads(maxThreads.intValue());
650 }
651 try {
652 qtp.start();
653 } catch (Exception e) {
654 throw new RuntimeCamelException("Error starting JettyServer thread pool: " + qtp, e);
655 }
656 server.setThreadPool(qtp);
657 }
658
659 if (getThreadPool() != null) {
660 server.setThreadPool(getThreadPool());
661 }
662
663 return server;
664 }
665
666 /**
667 * Starts {@link #mbContainer} and registers the container with itself as a managed bean
668 * logging an error if there is a problem starting the container.
669 * Does nothing if {@link #mbContainer} is {@code null}.
670 */
671 protected void startMbContainer() {
672 if (mbContainer != null && !mbContainer.isStarted()) {
673 try {
674 mbContainer.start();
675 // Publish the container itself for consistency with
676 // traditional embedded Jetty configurations.
677 mbContainer.addBean(mbContainer);
678 } catch (Throwable e) {
679 LOG.warn("Could not start Jetty MBeanContainer. Jetty JMX extensions will remain disabled.", e);
680 }
681 }
682 }
683
684 @Override
685 protected void doStart() throws Exception {
686 super.doStart();
687 if (httpClientThreadPool != null && httpClientThreadPool instanceof LifeCycle) {
688 LifeCycle lc = (LifeCycle) httpClientThreadPool;
689 lc.start();
690 }
691 if (httpClient != null && !httpClient.isStarted()) {
692 httpClient.start();
693 }
694
695 startMbContainer();
696 }
697
698 @Override
699 protected void doStop() throws Exception {
700 super.doStop();
701 if (CONNECTORS.size() > 0) {
702 for (String connectorKey : CONNECTORS.keySet()) {
703 ConnectorRef connectorRef = CONNECTORS.get(connectorKey);
704 if (connectorRef != null && connectorRef.getRefCount() == 0) {
705 connectorRef.server.removeConnector(connectorRef.connector);
706 connectorRef.connector.stop();
707 connectorRef.server.stop();
708 // Camel controls the lifecycle of these entities so remove the
709 // registered MBeans when Camel is done with the managed objects.
710 if (mbContainer != null) {
711 mbContainer.removeBean(connectorRef.server);
712 mbContainer.removeBean(connectorRef.connector);
713 }
714 CONNECTORS.remove(connectorKey);
715 }
716 }
717 }
718 if (httpClient != null) {
719 httpClient.stop();
720 }
721 if (httpClientThreadPool != null && httpClientThreadPool instanceof LifeCycle) {
722 LifeCycle lc = (LifeCycle) httpClientThreadPool;
723 lc.stop();
724 }
725 if (mbContainer != null) {
726 mbContainer.stop();
727 }
728 }
729 }