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.commons.util.CollectionFactory;
018import org.apache.tapestry5.ioc.annotations.PostInjection;
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 (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            @Override
071            public void run()
072            {
073                registryDidShutdown();
074            }
075        });
076    }
077
078    @Override
079    public void register(Object bean, String name)
080    {
081        register(bean, toObjectName(name));
082    }
083
084    private static ObjectName toObjectName(String name)
085    {
086        try
087        {
088            return new ObjectName(name);
089        } catch (Exception ex)
090        {
091            throw new RuntimeException(ex);
092        }
093    }
094
095    @Override
096    public void register(final Object object, final ObjectName objectName)
097    {
098        lock.check();
099
100        if (this.server.isRegistered(objectName))
101            return;
102
103        try
104        {
105            this.server.registerMBean(object, objectName);
106
107            this.registeredBeans.add(objectName);
108
109            this.logger.info(format("Registered MBean '%s' with server", objectName));
110        } catch (final Exception e)
111        {
112            this.logger.error(format("Failed to register MBean '%s' with server", objectName), e);
113        }
114    }
115
116    @Override
117    public void unregister(final ObjectName objectName)
118    {
119        lock.check();
120
121        doUnregister(objectName);
122    }
123
124    private void doUnregister(final ObjectName objectName)
125    {
126        if (this.server.isRegistered(objectName))
127        {
128            try
129            {
130                this.server.unregisterMBean(objectName);
131
132                this.logger.info(format("Unregistered MBean '%s' from server", objectName));
133
134                if (registeredBeans.contains(objectName))
135                    registeredBeans.remove(objectName);
136            } catch (final Exception e)
137            {
138                this.logger.error(String.format("Failed to unregister MBean '%s' from server", objectName), e);
139            }
140        }
141    }
142
143    private void registryDidShutdown()
144    {
145        lock.lock();
146        // store into new data structure so we can remove them from registered beans
147        ObjectName[] objects = registeredBeans.toArray(new ObjectName[registeredBeans.size()]);
148        for (final ObjectName name : objects)
149        {
150            doUnregister(name);
151        }
152
153        this.registeredBeans.clear();
154
155    }
156}