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