001    /**
002     *
003     * Copyright 2003-2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  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.tomcat;
018    
019    import java.util.ArrayList;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Set;
023    import org.apache.commons.logging.Log;
024    import org.apache.commons.logging.LogFactory;
025    import org.apache.geronimo.gbean.AbstractName;
026    import org.apache.geronimo.gbean.AbstractNameQuery;
027    import org.apache.geronimo.gbean.GBeanData;
028    import org.apache.geronimo.gbean.GBeanInfo;
029    import org.apache.geronimo.gbean.GBeanInfoBuilder;
030    import org.apache.geronimo.gbean.ReferencePatterns;
031    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
032    import org.apache.geronimo.kernel.GBeanNotFoundException;
033    import org.apache.geronimo.kernel.Kernel;
034    import org.apache.geronimo.kernel.config.ConfigurationUtil;
035    import org.apache.geronimo.kernel.config.EditableConfigurationManager;
036    import org.apache.geronimo.kernel.config.InvalidConfigException;
037    import org.apache.geronimo.kernel.proxy.ProxyManager;
038    import org.apache.geronimo.management.geronimo.NetworkConnector;
039    import org.apache.geronimo.management.geronimo.WebAccessLog;
040    import org.apache.geronimo.management.geronimo.WebConnector;
041    import org.apache.geronimo.management.geronimo.WebContainer;
042    import org.apache.geronimo.management.geronimo.WebManager;
043    import org.apache.geronimo.system.serverinfo.ServerInfo;
044    
045    /**
046     * Tomcat implementation of the WebManager management API.  Knows how to
047     * manipulate other Tomcat objects for management purposes.
048     *
049     * @version $Rev: 406807 $ $Date: 2006-05-15 19:50:45 -0700 (Mon, 15 May 2006) $
050     */
051    public class TomcatManagerImpl implements WebManager {
052        private final static Log log = LogFactory.getLog(TomcatManagerImpl.class);
053        private final Kernel kernel;
054    
055        public TomcatManagerImpl(Kernel kernel) {
056            this.kernel = kernel;
057        }
058    
059        public String getProductName() {
060            return "Tomcat";
061        }
062    
063        /**
064         * Creates and returns a new connector.  Note that the connector may well
065         * require further customization before being fully functional (e.g. SSL
066         * settings for a secure connector).  This may need to be done before
067         * starting the resulting connector.
068         *
069         * @param container    The container to add the connector to
070         * @param uniqueName   A name fragment that's unique to this connector
071         * @param protocol     The protocol that the connector should use
072         * @param host         The host name or IP that the connector should listen on
073         * @param port         The port that the connector should listen on
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, ConnectorGBean.GBEAN_INFO);
081            } else if(protocol.equals(PROTOCOL_HTTPS)) {
082                connector = new GBeanData(name, HttpsConnectorGBean.GBEAN_INFO);
083                AbstractNameQuery query = new AbstractNameQuery(ServerInfo.class.getName());
084                Set set = kernel.listGBeans(query);
085                connector.setReferencePattern("ServerInfo", (AbstractName)set.iterator().next());
086                //todo: default HTTPS settings
087            } else if(protocol.equals(PROTOCOL_AJP)) {
088                connector = new GBeanData(name, ConnectorGBean.GBEAN_INFO);
089            } else {
090                throw new IllegalArgumentException("Invalid protocol '"+protocol+"'");
091            }
092            connector.setAttribute("protocol", protocol);
093            connector.setAttribute("host", host);
094            connector.setAttribute("port", new Integer(port));
095            connector.setAttribute("maxThreads", new Integer(50));
096            connector.setAttribute("acceptQueueSize", new Integer(100));
097            connector.setReferencePattern(ConnectorGBean.CONNECTOR_CONTAINER_REFERENCE, containerName);
098            connector.setAttribute("name", uniqueName);
099            EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel);
100            if(mgr != null) {
101                try {
102                    mgr.addGBeanToConfiguration(containerName.getArtifact(), connector, false);
103                    return (WebConnector) kernel.getProxyManager().createProxy(name, TomcatWebConnector.class.getClassLoader());
104                } catch (InvalidConfigException e) {
105                    log.error("Unable to add GBean", e);
106                    return null;
107                } finally {
108                    ConfigurationUtil.releaseConfigurationManager(kernel, mgr);
109                }
110            } else {
111                log.warn("The ConfigurationManager in the kernel does not allow editing");
112                return null;
113            }
114        }
115    
116        /**
117         * Gets the network containers.
118         */
119        public Object[] getContainers() {
120            ProxyManager proxyManager = kernel.getProxyManager();
121            AbstractNameQuery query = new AbstractNameQuery(TomcatWebContainer.class.getName());
122            Set names = kernel.listGBeans(query);
123            TomcatWebContainer[] results = new TomcatWebContainer[names.size()];
124            int i=0;
125            for (Iterator it = names.iterator(); it.hasNext(); i++) {
126                AbstractName name = (AbstractName) it.next();
127                results[i] = (TomcatWebContainer) proxyManager.createProxy(name, TomcatWebContainer.class.getClassLoader());
128            }
129            return results;
130        }
131    
132        /**
133         * Gets the protocols which this container can configure connectors for.
134         */
135        public String[] getSupportedProtocols() {
136            return new String[]{PROTOCOL_HTTP, PROTOCOL_HTTPS, PROTOCOL_AJP};
137        }
138    
139        /**
140         * Removes a connector.  This shuts it down if necessary, and removes it from the server environment.  It must be a
141         * connector that uses this network technology.
142         * @param connectorName
143         */
144        public void removeConnector(AbstractName connectorName) {
145            try {
146                GBeanInfo info = kernel.getGBeanInfo(connectorName);
147                boolean found = false;
148                Set intfs = info.getInterfaces();
149                for (Iterator it = intfs.iterator(); it.hasNext();) {
150                    String intf = (String) it.next();
151                    if (intf.equals(TomcatWebConnector.class.getName())) {
152                        found = true;
153                    }
154                }
155                if (!found) {
156                    throw new GBeanNotFoundException(connectorName);
157                }
158                EditableConfigurationManager mgr = ConfigurationUtil.getEditableConfigurationManager(kernel);
159                if(mgr != null) {
160                    try {
161                        mgr.removeGBeanFromConfiguration(connectorName.getArtifact(), connectorName);
162                    } catch (InvalidConfigException e) {
163                        log.error("Unable to add GBean", e);
164                    } finally {
165                        ConfigurationUtil.releaseConfigurationManager(kernel, mgr);
166                    }
167                } else {
168                    log.warn("The ConfigurationManager in the kernel does not allow editing");
169                }
170            } catch (GBeanNotFoundException e) {
171                log.warn("No such GBean '" + connectorName + "'"); //todo: what if we want to remove a failed GBean?
172            } catch (Exception e) {
173                log.error(e);
174            }
175        }
176    
177        /**
178         * Gets the ObjectNames of any existing connectors for this network technology for the specified 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(TomcatWebConnector.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, TomcatWebConnector.class.getClassLoader()));
195                    }
196                } catch (Exception e) {
197                    log.error("Unable to check the protocol for a connector", e);
198                }
199            }
200            return (TomcatWebConnector[]) result.toArray(new TomcatWebConnector[names.size()]);
201        }
202    
203        public WebAccessLog getAccessLog(WebContainer container) {
204            AbstractNameQuery query = new AbstractNameQuery(TomcatLogManager.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 Tomcat access log manager");
210            }
211            return (WebAccessLog) kernel.getProxyManager().createProxy((AbstractName)names.iterator().next(), TomcatLogManager.class.getClassLoader());
212        }
213    
214        /**
215         * Gets the ObjectNames of any existing connectors associated with this network technology.
216         */
217        public NetworkConnector[] getConnectors() {
218            ProxyManager proxyManager = kernel.getProxyManager();
219            AbstractNameQuery query = new AbstractNameQuery(TomcatWebConnector.class.getName());
220            Set names = kernel.listGBeans(query);
221            TomcatWebConnector[] results = new TomcatWebConnector[names.size()];
222            int i=0;
223            for (Iterator it = names.iterator(); it.hasNext(); i++) {
224                AbstractName name = (AbstractName) it.next();
225                results[i] = (TomcatWebConnector) proxyManager.createProxy(name, TomcatWebConnector.class.getClassLoader());
226            }
227            return results;
228        }
229    
230        /**
231         * Gets the ObjectNames of any existing connectors for the specified container for the specified protocol.
232         *
233         * @param protocol A protocol as returned by getSupportedProtocols
234         */
235        public NetworkConnector[] getConnectorsForContainer(Object container, String protocol) {
236            if(protocol == null) {
237                return getConnectorsForContainer(container);
238            }
239            AbstractName containerName = kernel.getAbstractNameFor(container);
240            ProxyManager mgr = kernel.getProxyManager();
241            try {
242                List results = new ArrayList();
243                AbstractNameQuery query = new AbstractNameQuery(TomcatWebConnector.class.getName());
244                Set set = kernel.listGBeans(query); // all Tomcat connectors
245                for (Iterator it = set.iterator(); it.hasNext();) {
246                    AbstractName name = (AbstractName) it.next(); // a single Tomcat connector
247                    GBeanData data = kernel.getGBeanData(name);
248                    ReferencePatterns refs = data.getReferencePatterns(ConnectorGBean.CONNECTOR_CONTAINER_REFERENCE);
249                    if(containerName.equals(refs.getAbstractName())) {
250                        try {
251                            String testProtocol = (String) kernel.getAttribute(name, "protocol");
252                            if(testProtocol != null && testProtocol.equals(protocol)) {
253                                results.add(mgr.createProxy(name, TomcatWebConnector.class.getClassLoader()));
254                            }
255                        } catch (Exception e) {
256                            log.error("Unable to look up protocol for connector '"+name+"'",e);
257                        }
258                        break;
259                    }
260                }
261                return (TomcatWebConnector[]) results.toArray(new TomcatWebConnector[results.size()]);
262            } catch (Exception e) {
263                throw (IllegalArgumentException)new IllegalArgumentException("Unable to look up connectors for Tomcat container '"+containerName +"': ").initCause(e);
264            }
265        }
266    
267        /**
268         * Gets the ObjectNames of any existing connectors for the specified container.
269         */
270        public NetworkConnector[] getConnectorsForContainer(Object container) {
271            AbstractName containerName = kernel.getAbstractNameFor(container);
272            ProxyManager mgr = kernel.getProxyManager();
273            try {
274                List results = new ArrayList();
275                AbstractNameQuery query = new AbstractNameQuery(TomcatWebConnector.class.getName());
276                Set set = kernel.listGBeans(query); // all Tomcat connectors
277                for (Iterator it = set.iterator(); it.hasNext();) {
278                    AbstractName name = (AbstractName) it.next(); // a single Tomcat connector
279                    GBeanData data = kernel.getGBeanData(name);
280                    ReferencePatterns refs = data.getReferencePatterns(ConnectorGBean.CONNECTOR_CONTAINER_REFERENCE);
281                    if (containerName.equals(refs.getAbstractName())) {
282                        results.add(mgr.createProxy(name, TomcatWebConnector.class.getClassLoader()));
283                    }
284                }
285                return (TomcatWebConnector[]) results.toArray(new TomcatWebConnector[results.size()]);
286            } catch (Exception e) {
287                throw (IllegalArgumentException) new IllegalArgumentException("Unable to look up connectors for Tomcat container '"+containerName).initCause(e);
288            }
289        }
290    
291        public static final GBeanInfo GBEAN_INFO;
292    
293        static {
294            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("Tomcat Web Manager", TomcatManagerImpl.class);
295            infoFactory.addAttribute("kernel", Kernel.class, false);
296            infoFactory.addInterface(WebManager.class);
297            infoFactory.setConstructor(new String[] {"kernel"});
298            GBEAN_INFO = infoFactory.getBeanInfo();
299        }
300    
301        public static GBeanInfo getGBeanInfo() {
302            return GBEAN_INFO;
303        }
304    }