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.geronimo.jetty6; 018 019 import java.util.ArrayList; 020 import java.util.Arrays; 021 import java.util.HashMap; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.Map.Entry; 026 import java.util.Set; 027 028 import org.apache.commons.logging.Log; 029 import org.apache.commons.logging.LogFactory; 030 import org.apache.geronimo.gbean.AbstractName; 031 import org.apache.geronimo.gbean.AbstractNameQuery; 032 import org.apache.geronimo.gbean.GBeanData; 033 import org.apache.geronimo.gbean.GBeanInfo; 034 import org.apache.geronimo.gbean.GBeanInfoBuilder; 035 import org.apache.geronimo.gbean.ReferencePatterns; 036 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 037 import org.apache.geronimo.jetty6.connector.AJP13Connector; 038 import org.apache.geronimo.jetty6.connector.HTTPBlockingConnector; 039 import org.apache.geronimo.jetty6.connector.HTTPSSelectChannelConnector; 040 import org.apache.geronimo.jetty6.connector.HTTPSSocketConnector; 041 import org.apache.geronimo.jetty6.connector.HTTPSelectChannelConnector; 042 import org.apache.geronimo.jetty6.connector.HTTPSocketConnector; 043 import org.apache.geronimo.jetty6.connector.JettyConnector; 044 import org.apache.geronimo.jetty6.requestlog.JettyLogManager; 045 import org.apache.geronimo.kernel.GBeanNotFoundException; 046 import org.apache.geronimo.kernel.Kernel; 047 import org.apache.geronimo.kernel.config.ConfigurationUtil; 048 import org.apache.geronimo.kernel.config.EditableConfigurationManager; 049 import org.apache.geronimo.kernel.config.InvalidConfigException; 050 import org.apache.geronimo.kernel.proxy.ProxyManager; 051 import org.apache.geronimo.management.geronimo.KeystoreManager; 052 import org.apache.geronimo.management.geronimo.NetworkConnector; 053 import org.apache.geronimo.management.geronimo.WebAccessLog; 054 import org.apache.geronimo.management.geronimo.WebContainer; 055 import org.apache.geronimo.management.geronimo.WebManager; 056 import org.apache.geronimo.management.geronimo.WebManager.ConnectorAttribute; 057 058 /** 059 * Jetty implementation of WebManager. Knows how to manipulate 060 * other Jetty objects for management purposes. 061 * 062 * @version $Rev:386276 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 063 */ 064 public class JettyManagerImpl implements WebManager { 065 private final static Log log = LogFactory.getLog(JettyManagerImpl.class); 066 067 private static final ConnectorType HTTP_NIO = new ConnectorType(Messages.getString("JettyManagerImpl.0")); //$NON-NLS-1$ 068 private static final ConnectorType HTTPS_NIO = new ConnectorType(Messages.getString("JettyManagerImpl.1")); //$NON-NLS-1$ 069 private static final ConnectorType HTTP_BLOCKING_NIO = new ConnectorType(Messages.getString("JettyManagerImpl.2")); //$NON-NLS-1$ 070 private static final ConnectorType HTTP_BIO = new ConnectorType(Messages.getString("JettyManagerImpl.3")); //$NON-NLS-1$ 071 private static final ConnectorType HTTPS_BIO = new ConnectorType(Messages.getString("JettyManagerImpl.4")); //$NON-NLS-1$ 072 private static final ConnectorType AJP_NIO = new ConnectorType(Messages.getString("JettyManagerImpl.5")); //$NON-NLS-1$ 073 private static List<ConnectorType> CONNECTOR_TYPES = Arrays.asList( 074 HTTP_NIO, 075 HTTPS_NIO, 076 HTTP_BLOCKING_NIO, 077 HTTP_BIO, 078 HTTPS_BIO, 079 AJP_NIO 080 ); 081 082 private static Map<ConnectorType, List<ConnectorAttribute>> CONNECTOR_ATTRIBUTES = new HashMap<ConnectorType, List<ConnectorAttribute>>(); 083 084 static { 085 List<ConnectorAttribute> connectorAttributes = new ArrayList<ConnectorAttribute>(); 086 addCommonConnectorAttributes(connectorAttributes); 087 CONNECTOR_ATTRIBUTES.put(HTTP_NIO, connectorAttributes); 088 089 connectorAttributes = new ArrayList<ConnectorAttribute>(); 090 addCommonConnectorAttributes(connectorAttributes); 091 addSslConnectorAttributes(connectorAttributes); 092 setAttribute(connectorAttributes, "port", 8443); // SSL port 093 CONNECTOR_ATTRIBUTES.put(HTTPS_NIO, connectorAttributes); 094 095 connectorAttributes = new ArrayList<ConnectorAttribute>(); 096 addCommonConnectorAttributes(connectorAttributes); 097 CONNECTOR_ATTRIBUTES.put(HTTP_BIO, connectorAttributes); 098 099 connectorAttributes = new ArrayList<ConnectorAttribute>(); 100 addCommonConnectorAttributes(connectorAttributes); 101 addSslConnectorAttributes(connectorAttributes); 102 setAttribute(connectorAttributes, "port", 8443); // SSL port 103 CONNECTOR_ATTRIBUTES.put(HTTPS_BIO, connectorAttributes); 104 105 connectorAttributes = new ArrayList<ConnectorAttribute>(); 106 addCommonConnectorAttributes(connectorAttributes); 107 CONNECTOR_ATTRIBUTES.put(HTTP_BLOCKING_NIO, connectorAttributes); 108 109 connectorAttributes = new ArrayList<ConnectorAttribute>(); 110 addCommonConnectorAttributes(connectorAttributes); 111 CONNECTOR_ATTRIBUTES.put(AJP_NIO, connectorAttributes); 112 113 } 114 115 private static Map<ConnectorType, GBeanInfo> CONNECTOR_GBEAN_INFOS = new HashMap<ConnectorType, GBeanInfo>(); 116 117 static { 118 CONNECTOR_GBEAN_INFOS.put(HTTP_NIO, HTTPSelectChannelConnector.GBEAN_INFO); 119 CONNECTOR_GBEAN_INFOS.put(HTTPS_NIO, HTTPSSelectChannelConnector.GBEAN_INFO); 120 CONNECTOR_GBEAN_INFOS.put(HTTP_BLOCKING_NIO, HTTPBlockingConnector.GBEAN_INFO); 121 CONNECTOR_GBEAN_INFOS.put(HTTP_BIO, HTTPSocketConnector.GBEAN_INFO); 122 CONNECTOR_GBEAN_INFOS.put(HTTPS_BIO, HTTPSSocketConnector.GBEAN_INFO); 123 CONNECTOR_GBEAN_INFOS.put(AJP_NIO, AJP13Connector.GBEAN_INFO); 124 } 125 126 private final Kernel kernel; 127 128 public JettyManagerImpl(Kernel kernel) { 129 this.kernel = kernel; 130 } 131 132 public String getProductName() { 133 return "Jetty"; 134 } 135 136 /** 137 * Get a list of containers for this web implementation. 138 */ 139 public Object[] getContainers() { 140 ProxyManager proxyManager = kernel.getProxyManager(); 141 AbstractNameQuery query = new AbstractNameQuery(JettyContainer.class.getName()); 142 Set names = kernel.listGBeans(query); 143 JettyContainer[] results = new JettyContainer[names.size()]; 144 int i = 0; 145 for (Iterator it = names.iterator(); it.hasNext(); i++) { 146 AbstractName name = (AbstractName) it.next(); 147 results[i] = (JettyContainer) proxyManager.createProxy(name, JettyContainer.class.getClassLoader()); 148 } 149 return results; 150 } 151 152 /** 153 * Gets the protocols that this web container supports (that you can create 154 * connectors for). 155 */ 156 public String[] getSupportedProtocols() { 157 return new String[]{PROTOCOL_HTTP, PROTOCOL_HTTPS, PROTOCOL_AJP}; 158 } 159 160 /** 161 * Removes a connector. This shuts it down if necessary, and removes it 162 * from the server environment. It must be a connector that this container 163 * is responsible for. 164 * 165 * @param connectorName 166 */ 167 public void removeConnector(AbstractName connectorName) { 168 try { 169 GBeanInfo info = kernel.getGBeanInfo(connectorName); 170 boolean found = false; 171 Set intfs = info.getInterfaces(); 172 for (Iterator it = intfs.iterator(); it.hasNext();) { 173 String intf = (String) it.next(); 174 if (intf.equals(JettyWebConnector.class.getName())) { 175 found = true; 176 } 177 } 178 if (!found) { 179 throw new GBeanNotFoundException(connectorName); 180 } 181 EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel); 182 if (mgr != null) { 183 try { 184 mgr.removeGBeanFromConfiguration(connectorName.getArtifact(), connectorName); 185 } catch (InvalidConfigException e) { 186 log.error("Unable to add GBean", e); 187 } finally { 188 ConfigurationUtil.releaseConfigurationManager(kernel, mgr); 189 } 190 } else { 191 log.warn("The ConfigurationManager in the kernel does not allow editing"); 192 } 193 } catch (GBeanNotFoundException e) { 194 log.warn("No such GBean '" + connectorName + "'"); //todo: what if we want to remove a failed GBean? 195 } catch (Exception e) { 196 log.error(e); 197 } 198 } 199 200 /** 201 * Gets the ObjectNames of any existing connectors for the specified 202 * protocol. 203 * 204 * @param protocol A protocol as returned by getSupportedProtocols 205 */ 206 public NetworkConnector[] getConnectors(String protocol) { 207 if (protocol == null) { 208 return getConnectors(); 209 } 210 List result = new ArrayList(); 211 ProxyManager proxyManager = kernel.getProxyManager(); 212 AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName()); 213 Set names = kernel.listGBeans(query); 214 for (Iterator it = names.iterator(); it.hasNext();) { 215 AbstractName name = (AbstractName) it.next(); 216 try { 217 if (kernel.getAttribute(name, "protocol").equals(protocol)) { 218 result.add(proxyManager.createProxy(name, JettyWebConnector.class.getClassLoader())); 219 } 220 } catch (Exception e) { 221 log.error("Unable to check the protocol for a connector", e); 222 } 223 } 224 return (JettyWebConnector[]) result.toArray(new JettyWebConnector[names.size()]); 225 } 226 227 public WebAccessLog getAccessLog(WebContainer container) { 228 AbstractNameQuery query = new AbstractNameQuery(JettyLogManager.class.getName()); 229 Set names = kernel.listGBeans(query); 230 if (names.size() == 0) { 231 return null; 232 } else if (names.size() > 1) { 233 throw new IllegalStateException("Should not be more than one Jetty access log manager"); 234 } 235 return (WebAccessLog) kernel.getProxyManager().createProxy((AbstractName) names.iterator().next(), JettyLogManager.class.getClassLoader()); 236 } 237 238 public List<ConnectorType> getConnectorTypes() { 239 return CONNECTOR_TYPES; 240 } 241 242 public List<ConnectorAttribute> getConnectorAttributes(ConnectorType connectorType) { 243 return ConnectorAttribute.copy(CONNECTOR_ATTRIBUTES.get(connectorType)); 244 } 245 246 public AbstractName getConnectorConfiguration(ConnectorType connectorType, List<ConnectorAttribute> connectorAttributes, WebContainer container, String uniqueName) { 247 GBeanInfo gbeanInfo = CONNECTOR_GBEAN_INFOS.get(connectorType); 248 AbstractName containerName = kernel.getAbstractNameFor(container); 249 AbstractName name = kernel.getNaming().createSiblingName(containerName, uniqueName, NameFactory.GERONIMO_SERVICE); 250 GBeanData gbeanData = new GBeanData(name, gbeanInfo); 251 gbeanData.setReferencePattern(JettyConnector.CONNECTOR_CONTAINER_REFERENCE, containerName); 252 for (ConnectorAttribute connectorAttribute : connectorAttributes) { 253 Object value = connectorAttribute.getValue(); 254 if (value != null) { 255 gbeanData.setAttribute(connectorAttribute.getAttributeName(), connectorAttribute.getValue()); 256 } 257 } 258 259 // provide a reference to KeystoreManager gbean for HTTPS connectors 260 if (connectorType.equals(HTTPS_NIO) || connectorType.equals(HTTPS_BIO)) { 261 AbstractNameQuery query = new AbstractNameQuery(KeystoreManager.class.getName()); 262 gbeanData.setReferencePattern("KeystoreManager", query); 263 } 264 265 EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel); 266 if (mgr != null) { 267 try { 268 mgr.addGBeanToConfiguration(containerName.getArtifact(), gbeanData, false); 269 } catch (InvalidConfigException e) { 270 log.error("Unable to add GBean", e); 271 return null; 272 } finally { 273 ConfigurationUtil.releaseConfigurationManager(kernel, mgr); 274 } 275 } else { 276 log.warn("The ConfigurationManager in the kernel does not allow editing"); 277 return null; 278 } 279 return name; 280 } 281 282 public ConnectorType getConnectorType(AbstractName connectorName) { 283 ConnectorType connectorType = null; 284 try { 285 GBeanInfo info = kernel.getGBeanInfo(connectorName); 286 boolean found = false; 287 Set intfs = info.getInterfaces(); 288 for (Iterator it = intfs.iterator(); it.hasNext() && !found;) { 289 String intf = (String) it.next(); 290 if (intf.equals(JettyWebConnector.class.getName())) { 291 found = true; 292 } 293 } 294 if (!found) { 295 throw new GBeanNotFoundException(connectorName); 296 } 297 String searchingFor = info.getName(); 298 for (Entry<ConnectorType, GBeanInfo> entry : CONNECTOR_GBEAN_INFOS.entrySet() ) { 299 String candidate = entry.getValue().getName(); 300 if (candidate.equals(searchingFor)) { 301 return entry.getKey(); 302 } 303 } 304 } catch (GBeanNotFoundException e) { 305 log.warn("No such GBean '" + connectorName + "'"); 306 } catch (Exception e) { 307 log.error(e); 308 } 309 310 return connectorType; 311 } 312 313 /** 314 * Gets the ObjectNames of any existing connectors. 315 */ 316 public NetworkConnector[] getConnectors() { 317 ProxyManager proxyManager = kernel.getProxyManager(); 318 AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName()); 319 Set names = kernel.listGBeans(query); 320 JettyWebConnector[] results = new JettyWebConnector[names.size()]; 321 int i = 0; 322 for (Iterator it = names.iterator(); it.hasNext(); i++) { 323 AbstractName name = (AbstractName) it.next(); 324 results[i] = (JettyWebConnector) proxyManager.createProxy(name, JettyWebConnector.class.getClassLoader()); 325 } 326 return results; 327 } 328 329 public NetworkConnector[] getConnectorsForContainer(Object container, String protocol) { 330 if (protocol == null) { 331 return getConnectorsForContainer(container); 332 } 333 AbstractName containerName = kernel.getAbstractNameFor(container); 334 ProxyManager mgr = kernel.getProxyManager(); 335 try { 336 List results = new ArrayList(); 337 AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName()); 338 Set set = kernel.listGBeans(query); // all Jetty connectors 339 for (Iterator it = set.iterator(); it.hasNext();) { 340 AbstractName name = (AbstractName) it.next(); // a single Jetty connector 341 GBeanData data = kernel.getGBeanData(name); 342 ReferencePatterns refs = data.getReferencePatterns(JettyConnector.CONNECTOR_CONTAINER_REFERENCE); 343 if (containerName.equals(refs.getAbstractName())) { 344 try { 345 String testProtocol = (String) kernel.getAttribute(name, "protocol"); 346 if (testProtocol != null && testProtocol.equals(protocol)) { 347 results.add(mgr.createProxy(name, JettyWebConnector.class.getClassLoader())); 348 } 349 } catch (Exception e) { 350 log.error("Unable to look up protocol for connector '" + name + "'", e); 351 } 352 break; 353 } 354 } 355 return (JettyWebConnector[]) results.toArray(new JettyWebConnector[results.size()]); 356 } catch (Exception e) { 357 throw (IllegalArgumentException) new IllegalArgumentException("Unable to look up connectors for Jetty container '" + containerName + "': ").initCause(e); 358 } 359 } 360 361 public NetworkConnector[] getConnectorsForContainer(Object container) { 362 AbstractName containerName = kernel.getAbstractNameFor(container); 363 ProxyManager mgr = kernel.getProxyManager(); 364 try { 365 List results = new ArrayList(); 366 AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName()); 367 Set set = kernel.listGBeans(query); // all Jetty connectors 368 for (Iterator it = set.iterator(); it.hasNext();) { 369 AbstractName name = (AbstractName) it.next(); // a single Jetty connector 370 GBeanData data = kernel.getGBeanData(name); 371 ReferencePatterns refs = data.getReferencePatterns(JettyConnector.CONNECTOR_CONTAINER_REFERENCE); 372 if (containerName.equals(refs.getAbstractName())) { 373 results.add(mgr.createProxy(name, JettyWebConnector.class.getClassLoader())); 374 } 375 } 376 return (JettyWebConnector[]) results.toArray(new JettyWebConnector[results.size()]); 377 } catch (Exception e) { 378 throw (IllegalArgumentException) new IllegalArgumentException("Unable to look up connectors for Jetty container '" + containerName + "'").initCause(e); 379 } 380 } 381 382 private static void addCommonConnectorAttributes(List<ConnectorAttribute> connectorAttributes) { 383 connectorAttributes.add(new ConnectorAttribute<String>("host", "0.0.0.0", Messages.getString("JettyManagerImpl.30"), String.class, true)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 384 connectorAttributes.add(new ConnectorAttribute<Integer>("port", 8080, Messages.getString("JettyManagerImpl.32"), Integer.class, true)); //$NON-NLS-1$ //$NON-NLS-2$ 385 connectorAttributes.add(new ConnectorAttribute<Integer>("maxThreads", 10, Messages.getString("JettyManagerImpl.34"), Integer.class)); //$NON-NLS-1$ //$NON-NLS-2$ 386 connectorAttributes.add(new ConnectorAttribute<Integer>("bufferSizeBytes", 8096, Messages.getString("JettyManagerImpl.36"), Integer.class)); //$NON-NLS-1$ //$NON-NLS-2$ 387 connectorAttributes.add(new ConnectorAttribute<Integer>("headerBufferSizeBytes", 8192, Messages.getString("JettyManagerImpl.57"), Integer.class)); //$NON-NLS-1$ //$NON-NLS-2$ 388 connectorAttributes.add(new ConnectorAttribute<Integer>("acceptQueueSize", 10, Messages.getString("JettyManagerImpl.38"), Integer.class)); //$NON-NLS-1$ //$NON-NLS-2$ 389 connectorAttributes.add(new ConnectorAttribute<Integer>("lingerMillis", 30000, Messages.getString("JettyManagerImpl.40"), Integer.class)); //$NON-NLS-1$ //$NON-NLS-2$ 390 //connectorAttributes.add(new ConnectorAttribute<Boolean>("tcpNoDelay", false, "If true then setTcpNoDelay(true) is called on accepted sockets.", Boolean.class)); 391 connectorAttributes.add(new ConnectorAttribute<Integer>("redirectPort", 8443, Messages.getString("JettyManagerImpl.42"), Integer.class)); //$NON-NLS-1$ //$NON-NLS-2$ 392 //connectorAttributes.add(new ConnectorAttribute<Integer>("maxIdleTimeMs", 30000, " The time in milliseconds that a connection can be idle before being closed.", Integer.class)); 393 } 394 395 private static void addSslConnectorAttributes(List<ConnectorAttribute> connectorAttributes) { 396 //connectorAttributes.add(new ConnectorAttribute<Boolean>("clientAuthRequested", false, "clientAuthRequested", Boolean.class)); 397 connectorAttributes.add(new ConnectorAttribute<Boolean>("clientAuthRequired", false, Messages.getString("JettyManagerImpl.44"), Boolean.class)); //$NON-NLS-1$ //$NON-NLS-2$ 398 connectorAttributes.add(new ConnectorAttribute<String>("keyStore", "", Messages.getString("JettyManagerImpl.47"), String.class, true)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 399 connectorAttributes.add(new ConnectorAttribute<String>("trustStore", "", Messages.getString("JettyManagerImpl.50"), String.class)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 400 //connectorAttributes.add(new ConnectorAttribute<String>("keyAlias", "", "keyAlias", String.class, true)); 401 connectorAttributes.add(new ConnectorAttribute<String>("secureProtocol", "", Messages.getString("JettyManagerImpl.53"), String.class)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 402 connectorAttributes.add(new ConnectorAttribute<String>("algorithm", "Default", Messages.getString("JettyManagerImpl.56"), String.class)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 403 } 404 405 private static <T> void setAttribute (List<ConnectorAttribute> connectorAttributes, String attributeName, T value) { 406 for (ConnectorAttribute connectorAttribute : connectorAttributes) { 407 if (connectorAttribute.getAttributeName().equals(attributeName)) { 408 connectorAttribute.setValue(value); 409 return; 410 } 411 } 412 } 413 414 public static final GBeanInfo GBEAN_INFO; 415 416 static { 417 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Jetty Web Manager", JettyManagerImpl.class); 418 infoFactory.addAttribute("kernel", Kernel.class, false); 419 infoFactory.addInterface(WebManager.class); 420 infoFactory.setConstructor(new String[]{"kernel"}); 421 GBEAN_INFO = infoFactory.getBeanInfo(); 422 } 423 424 public static GBeanInfo getGBeanInfo() { 425 return GBEAN_INFO; 426 } 427 }