001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.geronimo.tomcat; 019 020 import java.net.InetSocketAddress; 021 import java.net.UnknownHostException; 022 import java.net.InetAddress; 023 import java.util.Map; 024 import java.util.HashMap; 025 026 import org.apache.catalina.LifecycleException; 027 import org.apache.catalina.connector.Connector; 028 import org.apache.commons.logging.Log; 029 import org.apache.commons.logging.LogFactory; 030 import org.apache.geronimo.gbean.GBeanInfo; 031 import org.apache.geronimo.gbean.GBeanInfoBuilder; 032 import org.apache.geronimo.gbean.GBeanLifecycle; 033 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 034 import org.apache.geronimo.management.geronimo.WebManager; 035 036 /** 037 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $ 038 */ 039 public class ConnectorGBean extends BaseGBean implements GBeanLifecycle, ObjectRetriever, TomcatWebConnector { 040 private static final Log log = LogFactory.getLog(ConnectorGBean.class); 041 public final static String CONNECTOR_CONTAINER_REFERENCE = "TomcatContainer"; 042 043 protected final Connector connector; 044 private final TomcatContainer container; 045 private String name; 046 private String connectHost; 047 048 public ConnectorGBean(String name, String protocol, String host, int port, TomcatContainer container) throws Exception { 049 super(); // TODO: make it an attribute 050 051 Map initParams = new HashMap(); 052 053 validateProtocol(protocol); 054 055 //Default the host to listen on all address is one was not specified 056 if (host == null){ 057 host = "0.0.0.0"; 058 } 059 060 //Must have a port 061 if (port == 0){ 062 throw new IllegalArgumentException("Must declare a port."); 063 } 064 065 initParams.put("address", host); 066 initParams.put("port", Integer.toString(port)); 067 initializeParams(protocol, initParams); 068 069 // Convert Geronimo standard values to Tomcat standard values 070 // Only AJP requires an explicit protocol setting 071 if(protocol != null && protocol.equals(WebManager.PROTOCOL_AJP)) { 072 protocol = "AJP/1.3"; 073 } else { 074 protocol = null; 075 } 076 077 if (name == null){ 078 throw new IllegalArgumentException("name cannot be null."); 079 } 080 081 if (container == null){ 082 throw new IllegalArgumentException("container cannot be null."); 083 } 084 085 this.name = name; 086 this.container = container; 087 088 //Create the Connector object 089 connector = new Connector(protocol); 090 091 092 //Set the parameters 093 setParameters(connector, initParams); 094 095 } 096 097 /** 098 * Adds any special parameters before constructing the connector. Note: 099 * all keys and values must be Strings. 100 * 101 * @param protocol Should be one of the constants from WebContainer. 102 * @param params The map of parameters that will be used to initialize the connector. 103 */ 104 protected void initializeParams(String protocol, Map params) {} 105 106 /** 107 * Ensures that this implementation can handle the requested protocol. 108 * @param protocol 109 */ 110 protected void validateProtocol(String protocol) { 111 if(protocol == null) { 112 return; 113 } 114 if(protocol.equals(WebManager.PROTOCOL_HTTPS)) { 115 throw new IllegalArgumentException("Use a HttpsConnectorGBean for an HTTPS connector"); 116 } else if(!protocol.equals(WebManager.PROTOCOL_HTTP) && !protocol.equals(WebManager.PROTOCOL_AJP)) { 117 throw new IllegalArgumentException("Unrecognized protocol '"+protocol+"' (use the values of the PROTOCOL_* constants in WebConnector)"); 118 } 119 } 120 121 public String getName() { 122 return name; 123 } 124 125 public Object getInternalObject() { 126 return connector; 127 } 128 129 public void doStart() throws LifecycleException { 130 container.addConnector(connector); 131 connector.start(); 132 log.debug(name + " connector started"); 133 } 134 135 public void doStop() { 136 try{ 137 connector.stop(); 138 } catch (LifecycleException e){ 139 log.error(e); 140 } 141 container.removeConnector(connector); 142 log.debug(name + " connector stopped"); 143 } 144 145 public void doFail() { 146 log.warn(name + " connector failed"); 147 doStop(); 148 } 149 150 public int getDefaultPort() { 151 return getProtocol().equals(WebManager.PROTOCOL_AJP) ? -1 : 152 getProtocol().equals(WebManager.PROTOCOL_HTTP) ? 80 : 153 getProtocol().equals(WebManager.PROTOCOL_HTTPS) ? 443 : -1; 154 } 155 156 public String getConnectUrl() { 157 if(connectHost == null) { 158 String host = getHost(); 159 if(host == null || host.equals("0.0.0.0")) { 160 InetAddress address = null; 161 try { 162 address = InetAddress.getLocalHost(); 163 } catch (UnknownHostException e) { 164 host = "unknown-host"; 165 } 166 if(address != null) { 167 host = address.getCanonicalHostName(); 168 if(host == null || host.equals("")) { 169 host = address.getHostAddress(); 170 } 171 } 172 } 173 connectHost = host; 174 } 175 return getProtocol().toLowerCase()+"://"+connectHost+(getPort() == getDefaultPort() ? "" : ":"+getPort()); 176 } 177 178 public boolean isEmptySessionPath(){ 179 return connector.getEmptySessionPath(); 180 } 181 182 public void setEmptySessionPath(boolean emptySessionPath){ 183 connector.setEmptySessionPath(emptySessionPath); 184 } 185 186 /** 187 * Gets the network protocol that this connector handles. 188 */ 189 public String getProtocol() { 190 String protocol = connector.getProtocol(); 191 if(protocol.indexOf("AJP") > -1) { 192 return WebManager.PROTOCOL_AJP; 193 } else if(connector.getScheme().equalsIgnoreCase("http")) { 194 return WebManager.PROTOCOL_HTTP; 195 } else if(connector.getScheme().equalsIgnoreCase("https")) { 196 return WebManager.PROTOCOL_HTTPS; 197 } 198 throw new IllegalStateException("Unknown protocol '"+protocol+"' and scheme '"+connector.getScheme()+"'"); 199 } 200 201 /** 202 * Gets the network port that this connector listens on. 203 */ 204 public int getPort() { 205 return connector.getPort(); 206 } 207 208 /** 209 * Sets the network port that this connector listens on. 210 */ 211 public void setPort(int port) { 212 connector.setPort(port); 213 } 214 215 /** 216 * Gets the hostname/IP that this connector listens on. 217 */ 218 public String getHost() { 219 Object value = connector.getAttribute("address"); 220 if(value == null) { 221 return "0.0.0.0"; 222 } else if(value instanceof InetAddress) { 223 return ((InetAddress)value).getHostAddress(); 224 } else return value.toString(); 225 } 226 227 /** 228 * Sets the hostname/IP that this connector listens on. This is typically 229 * most useful for machines with multiple network cards, but can be used 230 * to limit a connector to only listen for connections from the local 231 * machine (127.0.0.1). To listen on all available network interfaces, 232 * specify an address of 0.0.0.0. 233 */ 234 public void setHost(String host) throws UnknownHostException { 235 connector.setAttribute("address", host); 236 } 237 238 /** 239 * Every connector must specify a property of type InetSocketAddress 240 * because we use that to identify the network services to print a list 241 * during startup. However, this can be read-only since the host and port 242 * are set separately using setHost and setPort. 243 */ 244 public InetSocketAddress getListenAddress() { 245 return new InetSocketAddress(getHost(), getPort()); 246 } 247 248 /** 249 * Gets the size of the buffer used to handle network data for this 250 * connector. 251 */ 252 public int getBufferSizeBytes() { 253 Object value = connector.getAttribute("bufferSize"); 254 return value == null ? 2048 : Integer.parseInt(value.toString()); 255 } 256 257 /** 258 * Gets the size of the buffer used to handle network data for this 259 * connector. 260 */ 261 public void setBufferSizeBytes(int bytes) { 262 connector.setAttribute("bufferSize", new Integer(bytes)); 263 } 264 265 /** 266 * Gets the maximum number of threads used to service connections from 267 * this connector. 268 */ 269 public int getMaxThreads() { 270 Object value = connector.getAttribute("maxThreads"); 271 return value == null ? 200 : Integer.parseInt(value.toString()); 272 } 273 274 /** 275 * Sets the maximum number of threads used to service connections from 276 * this connector. 277 */ 278 public void setMaxThreads(int threads) { 279 connector.setAttribute("maxThreads", new Integer(threads)); 280 } 281 282 /** 283 * Gets the maximum number of connections that may be queued while all 284 * threads are busy. Any requests received while the queue is full will 285 * be rejected. 286 */ 287 public int getAcceptQueueSize() { 288 Object value = connector.getAttribute("acceptCount"); 289 return value == null ? 10 : Integer.parseInt(value.toString()); 290 } 291 292 /** 293 * Sets the maximum number of connections that may be queued while all 294 * threads are busy. Any requests received while the queue is full will 295 * be rejected. 296 */ 297 public void setAcceptQueueSize(int size) { 298 connector.setAttribute("acceptCount", new Integer(size)); 299 } 300 301 /** 302 * Gets the amount of time the socket used by this connector will linger 303 * after being closed. -1 indicates that socket linger is disabled. 304 */ 305 public int getLingerMillis() { 306 Object value = connector.getAttribute("connectionLinger"); 307 return value == null ? -1 : Integer.parseInt(value.toString()); 308 } 309 310 /** 311 * Sets the amount of time the socket used by this connector will linger 312 * after being closed. Use -1 to disable socket linger. 313 */ 314 public void setLingerMillis(int millis) { 315 connector.setAttribute("connectionLinger", new Integer(millis)); 316 } 317 318 /** 319 * Gets whether the TCP_NODELAY flag is set for the sockets used by this 320 * connector. This usually enhances performance, so it should typically 321 * be set. 322 */ 323 public boolean isTcpNoDelay() { 324 Object value = connector.getAttribute("tcpNoDelay"); 325 return value == null ? true : new Boolean(value.toString()).booleanValue(); 326 } 327 328 /** 329 * Sets whether the TCP_NODELAY flag is set for the sockets used by this 330 * connector. This usually enhances performance, so it should typically 331 * be set. 332 */ 333 public void setTcpNoDelay(boolean enable) { 334 connector.setAttribute("tcpNoDelay", new Boolean(enable)); 335 } 336 337 /** 338 * Gets the network port to which traffic will be redirected if this 339 * connector handles insecure traffic and the request requires a secure 340 * connection. Needless to say, this should point to another connector 341 * configured for SSL. 342 */ 343 public int getRedirectPort() { 344 return connector.getRedirectPort(); 345 } 346 347 /** 348 * Gets the network port to which traffic will be redirected if this 349 * connector handles insecure traffic and the request requires a secure 350 * connection. Needless to say, this should point to another connector 351 * configured for SSL. If no SSL connector is available, any port can 352 * be used as they all fail equally well. :) 353 */ 354 public void setRedirectPort(int port) { 355 connector.setRedirectPort(port); 356 } 357 358 public int getMinSpareThreads() { 359 Object value = connector.getAttribute("minSpareThreads"); 360 return value == null ? 4 : Integer.parseInt(value.toString()); 361 } 362 363 public void setMinSpareThreads(int threads) { 364 connector.setAttribute("minSpareThreads", new Integer(threads)); 365 } 366 367 public int getMaxSpareThreads() { 368 Object value = connector.getAttribute("maxSpareThreads"); 369 return value == null ? 50 : Integer.parseInt(value.toString()); 370 } 371 372 public void setMaxSpareThreads(int threads) { 373 connector.setAttribute("maxSpareThreads", new Integer(threads)); 374 } 375 376 public int getMaxHttpHeaderSizeBytes() { 377 Object value = connector.getAttribute("maxHttpHeaderSize"); 378 return value == null ? 4096 : Integer.parseInt(value.toString()); 379 } 380 381 public void setMaxHttpHeaderSizeBytes(int bytes) { 382 connector.setAttribute("maxHttpHeaderSize", new Integer(bytes)); 383 } 384 385 public boolean isHostLookupEnabled() { 386 return connector.getEnableLookups(); 387 } 388 389 public void setHostLookupEnabled(boolean enabled) { 390 connector.setEnableLookups(enabled); 391 } 392 393 public int getConnectionTimeoutMillis() { 394 Object value = connector.getAttribute("connectionTimeout"); 395 return value == null ? 60000 : Integer.parseInt(value.toString()); 396 } 397 398 public void setConnectionTimeoutMillis(int millis) { 399 connector.setAttribute("connectionTimeout", new Integer(millis)); 400 } 401 402 public boolean isUploadTimeoutEnabled() { 403 Object value = connector.getAttribute("disableUploadTimeout"); 404 return value == null ? true : !new Boolean(value.toString()).booleanValue(); 405 } 406 407 public void setUploadTimeoutEnabled(boolean enabled) { 408 connector.setAttribute("disableUploadTimeout", new Boolean(!enabled)); 409 } 410 411 public int getMaxPostSize() { 412 int value = connector.getMaxPostSize(); 413 return value == 0 ? 2097152 : value; 414 } 415 416 public void setMaxPostSize(int bytes) { 417 connector.setMaxPostSize(bytes); 418 } 419 420 public int getMaxSavePostSize() { 421 int value = connector.getMaxSavePostSize(); 422 return value == 0 ? 4096 : value; 423 } 424 425 public void setMaxSavePostSize(int kbytes) { 426 connector.setMaxSavePostSize(kbytes); 427 } 428 429 public int getMaxKeepAliveRequests() { 430 Object value = connector.getAttribute("maxKeepAliveRequests"); 431 return value == null ? 100 : Integer.parseInt(value.toString()); 432 } 433 434 public void setMaxKeepAliveRequests(int maxKeepAliveRequests) { 435 connector.setAttribute("maxKeepAliveRequests", new Integer(maxKeepAliveRequests)); 436 } 437 438 public int getSocketBuffer() { 439 Object value = connector.getAttribute("socketBuffer"); 440 return value == null ? 9000 : Integer.parseInt(value.toString()); 441 } 442 443 public void setSocketBuffer(int kbytes) { 444 connector.setAttribute("socketBuffer", new Integer(kbytes)); 445 } 446 447 public boolean getUseBodyEncodingForURI() { 448 return connector.getUseBodyEncodingForURI(); 449 } 450 451 public void setUseBodyEncodingForURI(boolean enabled) { 452 connector.setUseBodyEncodingForURI(enabled); 453 } 454 455 public void setAllowTrace(boolean allow) { 456 connector.setAllowTrace(allow); 457 } 458 459 public boolean getAllowTrace() { 460 return connector.getAllowTrace(); 461 } 462 463 public void setProxyName(String proxyName) { 464 connector.setProxyName(proxyName); 465 } 466 467 public String getProxyName() { 468 return connector.getProxyName(); 469 } 470 471 public void setProxyPort(int port) { 472 connector.setProxyPort(port); 473 } 474 475 public int getProxyPort() { 476 return connector.getProxyPort(); 477 } 478 479 public void setScheme(String scheme) { 480 connector.setScheme(scheme); 481 } 482 483 public String getScheme() { 484 return connector.getScheme(); 485 } 486 487 public void setUriEncoding(String encoding) { 488 connector.setURIEncoding(encoding); 489 } 490 491 public String getUriEncoding() { 492 return connector.getURIEncoding(); 493 } 494 495 public void setUseIPVHosts(boolean useIPVHosts) { 496 connector.setUseIPVHosts(useIPVHosts); 497 } 498 499 public boolean getUseIPVHosts() { 500 return connector.getUseIPVHosts(); 501 } 502 503 public void setXpoweredBy(boolean xpoweredBy) { 504 connector.setXpoweredBy(xpoweredBy); 505 } 506 507 public boolean getXpoweredBy() { 508 return connector.getXpoweredBy(); 509 } 510 511 public void setCompressableMimeType(String compressableMimeType) { 512 connector.setAttribute("compressableMimeType", compressableMimeType); 513 } 514 515 public String getCompressableMimeType() { 516 return (String) connector.getAttribute("compressableMimeType"); 517 } 518 519 public void setCompression(String compression) { 520 connector.setAttribute("compression", compression); 521 } 522 523 public String getCompression() { 524 return (String) connector.getAttribute("compression"); 525 } 526 527 public void setNoCompressionUserAgents(String noCompressionUserAgents) { 528 connector.setAttribute("noCompressionUserAgents", noCompressionUserAgents); 529 } 530 531 public String getNoCompressionUserAgents() { 532 return (String) connector.getAttribute("noCompressionUserAgents"); 533 } 534 535 public void setRestrictedUserAgents(String restrictedUserAgents) { 536 connector.setAttribute("restrictedUserAgents", restrictedUserAgents); 537 } 538 539 public String getRestrictedUserAgents() { 540 return (String) connector.getAttribute("restrictedUserAgents"); 541 } 542 543 public void setThreadPriority(int threadPriority) { 544 connector.setAttribute("threadPriority", new Integer(threadPriority)); 545 } 546 547 public int getThreadPriority() { 548 Object value = connector.getAttribute("threadPriority"); 549 return value == null ? 5 :Integer.parseInt(value.toString()); 550 } 551 552 public void setServer(String server) { 553 connector.setAttribute("server", server); 554 } 555 556 public String getServer() { 557 return (String) connector.getAttribute("server"); 558 } 559 560 public void setStrategy(String strategy) { 561 connector.setAttribute("strategy", strategy); 562 } 563 564 public String getStrategy() { 565 return (String) connector.getAttribute("strategy"); 566 } 567 568 public static final GBeanInfo GBEAN_INFO; 569 570 static { 571 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Tomcat Connector", ConnectorGBean.class); 572 infoFactory.addAttribute("name", String.class, true); 573 infoFactory.addAttribute("protocol", String.class, true); 574 infoFactory.addReference(CONNECTOR_CONTAINER_REFERENCE, TomcatContainer.class, NameFactory.GERONIMO_SERVICE); 575 infoFactory.addOperation("getInternalObject"); 576 infoFactory.addInterface(TomcatWebConnector.class, 577 new String[]{ 578 "host", 579 "port", 580 "bufferSizeBytes", 581 "maxThreads", 582 "acceptQueueSize", 583 "lingerMillis", 584 "tcpNoDelay", 585 "redirectPort", 586 "minSpareThreads", 587 "maxSpareThreads", 588 "maxHttpHeaderSizeBytes", 589 "hostLookupEnabled", 590 "connectionTimeoutMillis", 591 "uploadTimeoutEnabled", 592 "connectUrl", 593 "maxPostSize", 594 "maxSavePostSize", 595 "emptySessionPath", 596 "maxKeepAliveRequests", 597 "socketBuffer", 598 "useBodyEncodingForURI", 599 "allowTrace", 600 "proxyName", 601 "proxyPort", 602 "scheme", 603 "secure", 604 "uriEncoding", 605 "useIPVHosts", 606 "xpoweredBy", 607 "compressableMimeType", 608 "compression", 609 "noCompressionUserAgents", 610 "restrictedUserAgents", 611 "threadPriority", 612 "server", 613 "strategy" 614 }, 615 616 new String[]{ 617 "host", 618 "port", 619 "redirectPort", 620 "maxThreads"}); 621 infoFactory.setConstructor(new String[] { "name", "protocol", "host", "port", "TomcatContainer"}); 622 GBEAN_INFO = infoFactory.getBeanInfo(); 623 } 624 625 public static GBeanInfo getGBeanInfo() { 626 return GBEAN_INFO; 627 } 628 629 }