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
015package org.apache.tapestry5.internal.jmx;
016
017import org.apache.tapestry5.ioc.annotations.PostInjection;
018import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
019import org.apache.tapestry5.ioc.internal.util.OneShotLock;
020import org.apache.tapestry5.ioc.services.RegistryShutdownHub;
021import org.apache.tapestry5.jmx.MBeanSupport;
022import org.slf4j.Logger;
023
024import javax.management.MBeanServer;
025import javax.management.MBeanServerFactory;
026import javax.management.ObjectName;
027import java.lang.management.ManagementFactory;
028import java.util.List;
029import java.util.Set;
030
031import static java.lang.String.format;
032
033public 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}