001package org.cache2k.ee.impl;
002
003/*
004 * #%L
005 * cache2k ee
006 * %%
007 * Copyright (C) 2000 - 2016 headissue GmbH, Munich
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import org.cache2k.Cache;
024import org.cache2k.CacheManager;
025import org.cache2k.core.CacheLifeCycleListener;
026import org.cache2k.core.CacheManagerImpl;
027import org.cache2k.core.CacheManagerLifeCycleListener;
028import org.cache2k.core.InternalCache;
029
030import javax.management.InstanceNotFoundException;
031import javax.management.MBeanServer;
032import javax.management.ObjectName;
033import java.lang.management.ManagementFactory;
034import java.util.Map;
035import java.util.WeakHashMap;
036
037/**
038 * Adds optional support for JMX.
039 */
040public class JmxSupport implements CacheLifeCycleListener, CacheManagerLifeCycleListener {
041
042  int seenClassLoaderCount = 1;
043  Map<ClassLoader, Integer> classLoader2Integer = new WeakHashMap<ClassLoader, Integer>();
044
045  @Override
046  public void cacheCreated(CacheManager cm, Cache c) {
047    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
048    if (c instanceof InternalCache) {
049      String _name = standardName(cm, c);
050      try {
051         mbs.registerMBean(
052           new CacheMXBeanImpl((InternalCache) c),
053           new ObjectName(_name));
054      } catch (Exception e) {
055        throw new IllegalStateException("Error registering JMX bean, name='" + _name + "'", e);
056      }
057    }
058  }
059
060  @Override
061  public void cacheDestroyed(CacheManager cm, Cache c) {
062    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
063    if (c instanceof InternalCache) {
064      String _name = standardName(cm, c);
065      try {
066        mbs.unregisterMBean(new ObjectName(_name));
067      } catch (InstanceNotFoundException ignore) {
068      } catch (Exception e) {
069        throw new IllegalStateException("Error deregistering JMX bean, name='" + _name + "'", e);
070      }
071    }
072  }
073
074  @Override
075  public void managerCreated(CacheManager m) {
076    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
077    String _name = cacheManagerNameWithClassLoader(m);
078    try {
079      mbs.registerMBean(new ManagerMXBeanImpl((CacheManagerImpl) m),new ObjectName(_name));
080    } catch (Exception e) {
081      throw new IllegalStateException("Error register JMX bean, name='" + _name + "'", e);
082    }
083  }
084
085  @Override
086  public void managerDestroyed(CacheManager m) {
087    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
088    String _name = cacheManagerNameWithClassLoader(m);
089    try {
090      mbs.unregisterMBean(new ObjectName(_name));
091    } catch (InstanceNotFoundException ignore) {
092    } catch (Exception e) {
093      throw new IllegalStateException("Error unregister JMX bean, name='" + _name + "'", e);
094    }
095  }
096
097  private static String cacheManagerName(CacheManager cm) {
098    return
099      "org.cache2k" + ":" +
100      "type=CacheManager" +
101      ",name=" + cm.getName();
102  }
103
104  private static String cacheManagerNameWithClassLoaderNumber(CacheManager cm, int _classLoaderNumber) {
105    return
106      "org.cache2k" + ":" +
107      "type=CacheManager" +
108      ",name=" + cm.getName() +
109      ",uniqueClassLoaderNumber=" + _classLoaderNumber;
110  }
111
112  /**
113   * JSR107 allows cache managers with identical names within different class loaders.
114   * If multiple class loaders are involved, we need to add a qualifier to separate the names.
115   */
116  private synchronized int getUniqueClassLoaderNumber(ClassLoader _classLoader) {
117    Integer no = classLoader2Integer.get(_classLoader);
118    if (no == null) {
119      no = seenClassLoaderCount++;
120      classLoader2Integer.put(_classLoader, no);
121    }
122    return no;
123  }
124
125  private synchronized String cacheManagerNameWithClassLoader(CacheManager cm) {
126    ClassLoader _classLoader = cm.getClassLoader();
127    int no = getUniqueClassLoaderNumber(_classLoader);
128    if (no == 1) {
129      return cacheManagerName(cm);
130    }
131    return cacheManagerNameWithClassLoaderNumber(cm, no);
132  }
133
134  private synchronized String standardName(CacheManager cm, Cache c) {
135    int _classLoaderNumber = getUniqueClassLoaderNumber(cm.getClassLoader());
136    if (_classLoaderNumber == 1) {
137      return
138          "org.cache2k" + ":" +
139              "type=Cache" +
140              ",manager=" + cm.getName() +
141              ",name=" + c.getName();
142    }
143    return
144        "org.cache2k" + ":" +
145        "type=Cache" +
146        ",manager=" + cm.getName() +
147        ",uniqueClassLoaderNumber=" + _classLoaderNumber +
148        ",name=" + c.getName();
149
150  }
151
152}