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.system.jmx;
018    
019    import java.util.HashMap;
020    import java.util.Iterator;
021    import java.util.Map;
022    import java.util.Set;
023    import java.util.Collections;
024    import javax.management.InstanceAlreadyExistsException;
025    import javax.management.InstanceNotFoundException;
026    import javax.management.JMException;
027    import javax.management.JMRuntimeException;
028    import javax.management.MBeanInfo;
029    import javax.management.MBeanServer;
030    import javax.management.ObjectName;
031    
032    import org.apache.commons.logging.Log;
033    import org.apache.commons.logging.LogFactory;
034    import org.apache.geronimo.gbean.GBeanLifecycle;
035    import org.apache.geronimo.gbean.GBeanInfo;
036    import org.apache.geronimo.gbean.GBeanInfoBuilder;
037    import org.apache.geronimo.gbean.AbstractName;
038    import org.apache.geronimo.gbean.AbstractNameQuery;
039    import org.apache.geronimo.kernel.GBeanNotFoundException;
040    import org.apache.geronimo.kernel.Kernel;
041    import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter;
042    
043    /**
044     * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
045     */
046    public class MBeanServerKernelBridge implements GBeanLifecycle {
047        private static final Log log = LogFactory.getLog(MBeanServerKernelBridge.class);
048        private static final AbstractNameQuery ALL = new AbstractNameQuery(null, Collections.EMPTY_MAP, Collections.EMPTY_SET);
049    
050        private final HashMap registry = new HashMap();
051        private final Kernel kernel;
052        private final MBeanServer mbeanServer;
053    
054        // todo remove this as soon as Geronimo supports factory beans    
055        public MBeanServerKernelBridge(Kernel kernel, MBeanServerReference mbeanServerReference) {
056            this(kernel, mbeanServerReference.getMBeanServer());
057        }
058    
059        public MBeanServerKernelBridge(Kernel kernel, MBeanServer mbeanServer) {
060            this.kernel = kernel;
061            this.mbeanServer = mbeanServer;
062        }
063    
064        public void doStart() {
065            kernel.getLifecycleMonitor().addLifecycleListener(new GBeanRegistrationListener(), ALL);
066    
067            Set allNames = kernel.listGBeans(ALL);
068            for (Iterator iterator = allNames.iterator(); iterator.hasNext();) {
069                AbstractName abstractName = (AbstractName) iterator.next();
070                register(abstractName);
071            }
072        }
073    
074        public void doFail() {
075            doStop();
076        }
077    
078        public void doStop() {
079            // unregister all of our GBeans from the MBeanServer
080            Map beans;
081            synchronized (this) {
082                beans = new HashMap(registry);
083                registry.clear();
084            }
085            for (Iterator i = beans.values().iterator(); i.hasNext();) {
086                MBeanGBeanBridge mbeanGBeanBridge = (MBeanGBeanBridge) i.next();
087                ObjectName objectName = mbeanGBeanBridge.getObjectName();
088                try {
089                    mbeanServer.unregisterMBean(objectName);
090                } catch (Exception e) {
091                    // ignore
092                }
093            }
094        }
095    
096        private void register(AbstractName abstractName) {
097            try {
098                MBeanGBeanBridge mbeanGBeanBridge;
099                synchronized (this) {
100                    if (registry.containsKey(abstractName)) {
101                        return;
102                    }
103                    MBeanInfo mbeanInfo = JMXUtil.toMBeanInfo(kernel.getGBeanInfo(abstractName));
104                    mbeanGBeanBridge = new MBeanGBeanBridge(kernel, abstractName, abstractName.getObjectName(), mbeanInfo);
105                    registry.put(abstractName, mbeanGBeanBridge);
106                }
107                mbeanServer.registerMBean(mbeanGBeanBridge, mbeanGBeanBridge.getObjectName());
108            } catch (GBeanNotFoundException e) {
109                // ignore - gbean already unregistered
110            } catch (InstanceAlreadyExistsException e) {
111                // ignore - gbean already has an mbean shadow object
112            } catch (Exception e) {
113                log.warn("Unable to register MBean shadow object for GBean", unwrapJMException(e));
114            }
115        }
116    
117        private void unregister(AbstractName abstractName) {
118            MBeanGBeanBridge mbeanGBeanBridge;
119            synchronized (this) {
120                mbeanGBeanBridge = (MBeanGBeanBridge) registry.remove(abstractName);
121            }
122    
123            if (mbeanGBeanBridge != null) {
124                try {
125                    mbeanServer.unregisterMBean(mbeanGBeanBridge.getObjectName());
126                } catch (InstanceNotFoundException e) {
127                    // ignore - something else may have unregistered us
128                    // if there truely is no GBean then we will catch it below whwn we call the superclass
129                } catch (Exception e) {
130                    log.warn("Unable to unregister MBean shadow object for GBean", unwrapJMException(e));
131                }
132            }
133        }
134    
135        private Throwable unwrapJMException(Throwable cause) {
136            while ((cause instanceof JMException || cause instanceof JMRuntimeException) && cause.getCause() != null) {
137                cause = cause.getCause();
138            }
139            return cause;
140        }
141    
142        private class GBeanRegistrationListener extends LifecycleAdapter {
143            public void loaded(AbstractName abstractName) {
144                register(abstractName);
145            }
146    
147            public void unloaded(AbstractName abstractName) {
148                unregister(abstractName);
149            }
150        }
151    
152        public static final GBeanInfo GBEAN_INFO;
153    
154        static {
155            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(MBeanServerKernelBridge.class);
156            infoFactory.addAttribute("kernel", Kernel.class, false);
157            infoFactory.addReference("MBeanServerReference", MBeanServerReference.class);
158            infoFactory.setConstructor(new String[]{"kernel", "MBeanServerReference"});
159            GBEAN_INFO = infoFactory.getBeanInfo();
160        }
161    
162        public static GBeanInfo getGBeanInfo() {
163            return GBEAN_INFO;
164        }
165    }