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.jetty;
019    
020    import java.util.ArrayList;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Set;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.geronimo.gbean.AbstractName;
028    import org.apache.geronimo.gbean.AbstractNameQuery;
029    import org.apache.geronimo.gbean.GBeanData;
030    import org.apache.geronimo.gbean.GBeanInfo;
031    import org.apache.geronimo.gbean.GBeanInfoBuilder;
032    import org.apache.geronimo.gbean.ReferencePatterns;
033    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
034    import org.apache.geronimo.jetty.connector.AJP13Connector;
035    import org.apache.geronimo.jetty.connector.HTTPConnector;
036    import org.apache.geronimo.jetty.connector.HTTPSConnector;
037    import org.apache.geronimo.jetty.connector.JettyConnector;
038    import org.apache.geronimo.jetty.requestlog.JettyLogManager;
039    import org.apache.geronimo.kernel.GBeanNotFoundException;
040    import org.apache.geronimo.kernel.Kernel;
041    import org.apache.geronimo.kernel.config.ConfigurationUtil;
042    import org.apache.geronimo.kernel.config.EditableConfigurationManager;
043    import org.apache.geronimo.kernel.config.InvalidConfigException;
044    import org.apache.geronimo.kernel.proxy.ProxyManager;
045    import org.apache.geronimo.management.geronimo.KeystoreManager;
046    import org.apache.geronimo.management.geronimo.NetworkConnector;
047    import org.apache.geronimo.management.geronimo.WebAccessLog;
048    import org.apache.geronimo.management.geronimo.WebConnector;
049    import org.apache.geronimo.management.geronimo.WebContainer;
050    import org.apache.geronimo.management.geronimo.WebManager;
051    
052    /**
053     * Jetty implementation of WebManager.  Knows how to manipulate
054     * other Jetty objects for management purposes.
055     *
056     * @version $Rev:386276 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
057     */
058    public class JettyManagerImpl implements WebManager {
059        private final static Log log = LogFactory.getLog(JettyManagerImpl.class);
060        private final Kernel kernel;
061    
062        public JettyManagerImpl(Kernel kernel) {
063            this.kernel = kernel;
064        }
065    
066        public String getProductName() {
067            return "Jetty";
068        }
069    
070        /**
071         * Creates a new connector, and returns the ObjectName for it.  Note that
072         * the connector may well require further customization before being fully
073         * functional (e.g. SSL settings for an HTTPS connector).
074         */
075        public WebConnector addConnector(WebContainer container, String uniqueName, String protocol, String host, int port) {
076            AbstractName containerName = kernel.getAbstractNameFor(container);
077            AbstractName name = kernel.getNaming().createSiblingName(containerName, uniqueName, NameFactory.GERONIMO_SERVICE);
078            GBeanData connector;
079            if (protocol.equals(PROTOCOL_HTTP)) {
080                connector = new GBeanData(name, HTTPConnector.GBEAN_INFO);
081            } else if (protocol.equals(PROTOCOL_HTTPS)) {
082                connector = new GBeanData(name, HTTPSConnector.GBEAN_INFO);
083                AbstractNameQuery query = new AbstractNameQuery(KeystoreManager.class.getName());
084                connector.setReferencePattern("KeystoreManager", query);
085                //todo: default HTTPS settings
086            } else if (protocol.equals(PROTOCOL_AJP)) {
087                connector = new GBeanData(name, AJP13Connector.GBEAN_INFO);
088            } else {
089                throw new IllegalArgumentException("Invalid protocol '" + protocol + "'");
090            }
091            connector.setAttribute("host", host);
092            connector.setAttribute("port", new Integer(port));
093            connector.setAttribute("minThreads", new Integer(10));
094            connector.setAttribute("maxThreads", new Integer(50));
095            connector.setReferencePattern(JettyConnector.CONNECTOR_CONTAINER_REFERENCE, containerName);
096            EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel);
097            if(mgr != null) {
098                try {
099                    mgr.addGBeanToConfiguration(containerName.getArtifact(), connector, false);
100                    return (WebConnector) kernel.getProxyManager().createProxy(name, JettyWebConnector.class.getClassLoader());
101                } catch (InvalidConfigException e) {
102                    log.error("Unable to add GBean", e);
103                    return null;
104                } finally {
105                    ConfigurationUtil.releaseConfigurationManager(kernel, mgr);
106                }
107            } else {
108                log.warn("The ConfigurationManager in the kernel does not allow editing");
109                return null;
110            }
111        }
112    
113        /**
114         * Get a list of containers for this web implementation.
115         */
116        public Object[] getContainers() {
117            ProxyManager proxyManager = kernel.getProxyManager();
118            AbstractNameQuery query = new AbstractNameQuery(JettyContainer.class.getName());
119            Set names = kernel.listGBeans(query);
120            JettyContainer[] results = new JettyContainer[names.size()];
121            int i=0;
122            for (Iterator it = names.iterator(); it.hasNext(); i++) {
123                AbstractName name = (AbstractName) it.next();
124                results[i] = (JettyContainer) proxyManager.createProxy(name, JettyContainer.class.getClassLoader());
125            }
126            return results;
127        }
128    
129        /**
130         * Gets the protocols that this web container supports (that you can create
131         * connectors for).
132         */
133        public String[] getSupportedProtocols() {
134            return new String[]{PROTOCOL_HTTP, PROTOCOL_HTTPS, PROTOCOL_AJP};
135        }
136    
137        /**
138         * Removes a connector.  This shuts it down if necessary, and removes it
139         * from the server environment.  It must be a connector that this container
140         * is responsible for.
141         * @param connectorName
142         */
143        public void removeConnector(AbstractName connectorName) {
144            try {
145                GBeanInfo info = kernel.getGBeanInfo(connectorName);
146                boolean found = false;
147                Set intfs = info.getInterfaces();
148                for (Iterator it = intfs.iterator(); it.hasNext();) {
149                    String intf = (String) it.next();
150                    if (intf.equals(JettyWebConnector.class.getName())) {
151                        found = true;
152                    }
153                }
154                if (!found) {
155                    throw new GBeanNotFoundException(connectorName);
156                }
157                EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel);
158                if(mgr != null) {
159                    try {
160                        mgr.removeGBeanFromConfiguration(connectorName.getArtifact(), connectorName);
161                    } catch (InvalidConfigException e) {
162                        log.error("Unable to add GBean", e);
163                    } finally {
164                        ConfigurationUtil.releaseConfigurationManager(kernel, mgr);
165                    }
166                } else {
167                    log.warn("The ConfigurationManager in the kernel does not allow editing");
168                }
169            } catch (GBeanNotFoundException e) {
170                log.warn("No such GBean '" + connectorName + "'"); //todo: what if we want to remove a failed GBean?
171            } catch (Exception e) {
172                log.error(e);
173            }
174        }
175    
176        /**
177         * Gets the ObjectNames of any existing connectors for the specified
178         * protocol.
179         *
180         * @param protocol A protocol as returned by getSupportedProtocols
181         */
182        public NetworkConnector[] getConnectors(String protocol) {
183            if(protocol == null) {
184                return getConnectors();
185            }
186            List result = new ArrayList();
187            ProxyManager proxyManager = kernel.getProxyManager();
188            AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName());
189            Set names = kernel.listGBeans(query);
190            for (Iterator it = names.iterator(); it.hasNext();) {
191                AbstractName name = (AbstractName) it.next();
192                try {
193                    if (kernel.getAttribute(name, "protocol").equals(protocol)) {
194                        result.add(proxyManager.createProxy(name, JettyWebConnector.class.getClassLoader()));
195                    }
196                } catch (Exception e) {
197                    log.error("Unable to check the protocol for a connector", e);
198                }
199            }
200            return (JettyWebConnector[]) result.toArray(new JettyWebConnector[names.size()]);
201        }
202    
203        public WebAccessLog getAccessLog(WebContainer container) {
204            AbstractNameQuery query = new AbstractNameQuery(JettyLogManager.class.getName());
205            Set names = kernel.listGBeans(query);
206            if(names.size() == 0) {
207                return null;
208            } else if(names.size() > 1) {
209                throw new IllegalStateException("Should not be more than one Jetty access log manager");
210            }
211            return (WebAccessLog) kernel.getProxyManager().createProxy((AbstractName)names.iterator().next(), JettyLogManager.class.getClassLoader());
212        }
213    
214        /**
215         * Gets the ObjectNames of any existing connectors.
216         */
217        public NetworkConnector[] getConnectors() {
218            ProxyManager proxyManager = kernel.getProxyManager();
219            AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName());
220            Set names = kernel.listGBeans(query);
221            JettyWebConnector[] results = new JettyWebConnector[names.size()];
222            int i=0;
223            for (Iterator it = names.iterator(); it.hasNext(); i++) {
224                AbstractName name = (AbstractName) it.next();
225                results[i] = (JettyWebConnector) proxyManager.createProxy(name, JettyWebConnector.class.getClassLoader());
226            }
227            return results;
228        }
229    
230        public NetworkConnector[] getConnectorsForContainer(Object container, String protocol) {
231            if(protocol == null) {
232                return getConnectorsForContainer(container);
233            }
234            AbstractName containerName = kernel.getAbstractNameFor(container);
235            ProxyManager mgr = kernel.getProxyManager();
236            try {
237                List results = new ArrayList();
238                AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName());
239                Set set = kernel.listGBeans(query); // all Jetty connectors
240                for (Iterator it = set.iterator(); it.hasNext();) {
241                    AbstractName name = (AbstractName) it.next(); // a single Jetty connector
242                    GBeanData data = kernel.getGBeanData(name);
243                    ReferencePatterns refs = data.getReferencePatterns(JettyConnector.CONNECTOR_CONTAINER_REFERENCE);
244                    if(containerName.equals(refs.getAbstractName())) {
245                        try {
246                            String testProtocol = (String) kernel.getAttribute(name, "protocol");
247                            if(testProtocol != null && testProtocol.equals(protocol)) {
248                                results.add(mgr.createProxy(name, JettyWebConnector.class.getClassLoader()));
249                            }
250                        } catch (Exception e) {
251                            log.error("Unable to look up protocol for connector '"+name+"'",e);
252                        }
253                        break;
254                    }
255                }
256                return (JettyWebConnector[]) results.toArray(new JettyWebConnector[results.size()]);
257            } catch (Exception e) {
258                throw (IllegalArgumentException)new IllegalArgumentException("Unable to look up connectors for Jetty container '"+containerName +"': ").initCause(e);
259            }
260        }
261    
262        public NetworkConnector[] getConnectorsForContainer(Object container) {
263            AbstractName containerName = kernel.getAbstractNameFor(container);
264            ProxyManager mgr = kernel.getProxyManager();
265            try {
266                List results = new ArrayList();
267                AbstractNameQuery query = new AbstractNameQuery(JettyWebConnector.class.getName());
268                Set set = kernel.listGBeans(query); // all Jetty connectors
269                for (Iterator it = set.iterator(); it.hasNext();) {
270                    AbstractName name = (AbstractName) it.next(); // a single Jetty connector
271                    GBeanData data = kernel.getGBeanData(name);
272                    ReferencePatterns refs = data.getReferencePatterns(JettyConnector.CONNECTOR_CONTAINER_REFERENCE);
273                    if (containerName.equals(refs.getAbstractName())) {
274                        results.add(mgr.createProxy(name, JettyWebConnector.class.getClassLoader()));
275                    }
276                }
277                return (JettyWebConnector[]) results.toArray(new JettyWebConnector[results.size()]);
278            } catch (Exception e) {
279                throw (IllegalArgumentException) new IllegalArgumentException("Unable to look up connectors for Jetty container '"+containerName+"'").initCause(e);
280            }
281        }
282    
283        public static final GBeanInfo GBEAN_INFO;
284    
285        static {
286            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Jetty Web Manager", JettyManagerImpl.class);
287            infoFactory.addAttribute("kernel", Kernel.class, false);
288            infoFactory.addInterface(WebManager.class);
289            infoFactory.setConstructor(new String[] {"kernel"});
290            GBEAN_INFO = infoFactory.getBeanInfo();
291        }
292    
293        public static GBeanInfo getGBeanInfo() {
294            return GBEAN_INFO;
295        }
296    }