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 }