001    // Copyright 2010, 2011 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.internal.jmx;
016    
017    import org.apache.tapestry5.ioc.annotations.PostInjection;
018    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
019    import org.apache.tapestry5.ioc.internal.util.OneShotLock;
020    import org.apache.tapestry5.ioc.services.RegistryShutdownHub;
021    import org.apache.tapestry5.jmx.MBeanSupport;
022    import org.slf4j.Logger;
023    
024    import javax.management.MBeanServer;
025    import javax.management.MBeanServerFactory;
026    import javax.management.ObjectName;
027    import java.lang.management.ManagementFactory;
028    import java.util.List;
029    import java.util.Set;
030    
031    import static java.lang.String.format;
032    
033    public class MBeanSupportImpl implements MBeanSupport
034    {
035        private final Logger logger;
036    
037        private final MBeanServer server;
038    
039        private final OneShotLock lock = new OneShotLock();
040    
041        private final Set<ObjectName> registeredBeans = CollectionFactory.newSet();
042    
043        public MBeanSupportImpl(Logger logger)
044        {
045            this.logger = logger;
046    
047            // TODO: Agent Id should be configurable
048            final List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
049    
050            MBeanServer server = null;
051    
052            if (servers != null && 0 < servers.size())
053            {
054                server = servers.get(0);
055            }
056    
057            if (this.server == null)
058            {
059                server = ManagementFactory.getPlatformMBeanServer();
060            }
061    
062            this.server = server;
063        }
064    
065        @PostInjection
066        public void listenForShutdown(RegistryShutdownHub hub)
067        {
068            hub.addRegistryShutdownListener(new Runnable()
069            {
070                public void run()
071                {
072                    registryDidShutdown();
073                }
074            });
075        }
076    
077        public void register(Object bean, String name)
078        {
079            register(bean, toObjectName(name));
080        }
081    
082        private static ObjectName toObjectName(String name)
083        {
084            try
085            {
086                return new ObjectName(name);
087            } catch (Exception ex)
088            {
089                throw new RuntimeException(ex);
090            }
091        }
092    
093        public void register(final Object object, final ObjectName objectName)
094        {
095            lock.check();
096    
097            if (this.server.isRegistered(objectName))
098                return;
099    
100            try
101            {
102                this.server.registerMBean(object, objectName);
103    
104                this.registeredBeans.add(objectName);
105    
106                this.logger.info(format("Registered MBean '%s' with server", objectName));
107            } catch (final Exception e)
108            {
109                this.logger.error(format("Failed to register MBean '%s' with server", objectName), e);
110            }
111        }
112    
113        public void unregister(final ObjectName objectName)
114        {
115            lock.check();
116    
117            doUnregister(objectName);
118        }
119    
120        private void doUnregister(final ObjectName objectName)
121        {
122            if (this.server.isRegistered(objectName))
123            {
124                try
125                {
126                    this.server.unregisterMBean(objectName);
127    
128                    this.logger.info(format("Unregistered MBean '%s' from server", objectName));
129    
130                    if (registeredBeans.contains(objectName))
131                        registeredBeans.remove(objectName);
132                } catch (final Exception e)
133                {
134                    this.logger.error(String.format("Failed to unregister MBean '%s' from server", objectName), e);
135                }
136            }
137        }
138    
139        private void registryDidShutdown()
140        {
141            lock.lock();
142            // store into new data structure so we can remove them from registered beans
143            ObjectName[] objects = registeredBeans.toArray(new ObjectName[registeredBeans.size()]);
144            for (final ObjectName name : objects)
145            {
146                doUnregister(name);
147            }
148    
149            this.registeredBeans.clear();
150    
151        }
152    }