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 }