View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.jmx;
20  
21  import java.io.IOException;
22  import java.util.HashMap;
23  import java.util.Locale;
24  import java.util.Map;
25  import java.util.WeakHashMap;
26  
27  import javax.management.InstanceNotFoundException;
28  import javax.management.MBeanRegistrationException;
29  import javax.management.MBeanServer;
30  import javax.management.ObjectInstance;
31  import javax.management.ObjectName;
32  
33  import org.eclipse.jetty.util.component.Container;
34  import org.eclipse.jetty.util.component.ContainerLifeCycle;
35  import org.eclipse.jetty.util.component.Dumpable;
36  import org.eclipse.jetty.util.log.Log;
37  import org.eclipse.jetty.util.log.Logger;
38  
39  /**
40   * Container class for the MBean instances
41   */
42  public class MBeanContainer implements Container.InheritedListener, Dumpable
43  {
44      private final static Logger LOG = Log.getLogger(MBeanContainer.class.getName());
45  
46      private final MBeanServer _mbeanServer;
47      private final WeakHashMap<Object, ObjectName> _beans = new WeakHashMap<Object, ObjectName>();
48      private final HashMap<String, Integer> _unique = new HashMap<String, Integer>();
49      private String _domain = null;
50  
51      /**
52       * Lookup an object name by instance
53       *
54       * @param object instance for which object name is looked up
55       * @return object name associated with specified instance, or null if not found
56       */
57      public synchronized ObjectName findMBean(Object object)
58      {
59          ObjectName bean = _beans.get(object);
60          return bean == null ? null : bean;
61      }
62  
63      /**
64       * Lookup an instance by object name
65       *
66       * @param oname object name of instance
67       * @return instance associated with specified object name, or null if not found
68       */
69      public synchronized Object findBean(ObjectName oname)
70      {
71          for (Map.Entry<Object, ObjectName> entry : _beans.entrySet())
72          {
73              ObjectName bean = entry.getValue();
74              if (bean.equals(oname))
75                  return entry.getKey();
76          }
77          return null;
78      }
79  
80      /**
81       * Constructs MBeanContainer
82       *
83       * @param server instance of MBeanServer for use by container
84       */
85      public MBeanContainer(MBeanServer server)
86      {
87          _mbeanServer = server;
88      }
89  
90      /**
91       * Retrieve instance of MBeanServer used by container
92       *
93       * @return instance of MBeanServer
94       */
95      public MBeanServer getMBeanServer()
96      {
97          return _mbeanServer;
98      }
99  
100     /**
101      * Set domain to be used to add MBeans
102      *
103      * @param domain domain name
104      */
105     public void setDomain(String domain)
106     {
107         _domain = domain;
108     }
109 
110     /**
111      * Retrieve domain name used to add MBeans
112      *
113      * @return domain name
114      */
115     public String getDomain()
116     {
117         return _domain;
118     }
119 
120 
121     @Override
122     public void beanAdded(Container parent, Object obj)
123     {
124         LOG.debug("beanAdded {}->{}",parent,obj);
125         
126         // Is their an object name for the parent
127         ObjectName pname=null;
128         if (parent!=null)
129         {
130             pname=_beans.get(parent);
131             if (pname==null)
132             {
133                 // create the parent bean
134                 beanAdded(null,parent);
135                 pname=_beans.get(parent);
136             }
137         }
138         
139         // Does an mbean already exist?
140         if (obj == null || _beans.containsKey(obj))
141             return;
142         
143         try
144         {
145             // Create an MBean for the object
146             Object mbean = ObjectMBean.mbeanFor(obj);
147             if (mbean == null)
148                 return;
149 
150             
151             ObjectName oname = null;
152             if (mbean instanceof ObjectMBean)
153             {
154                 ((ObjectMBean)mbean).setMBeanContainer(this);
155                 oname = ((ObjectMBean)mbean).getObjectName();
156             }
157 
158             //no override mbean object name, so make a generic one
159             if (oname == null)
160             {      
161                 //if no explicit domain, create one
162                 String domain = _domain;
163                 if (domain == null)
164                     domain = obj.getClass().getPackage().getName();
165 
166 
167                 String type = obj.getClass().getName().toLowerCase(Locale.ENGLISH);
168                 int dot = type.lastIndexOf('.');
169                 if (dot >= 0)
170                     type = type.substring(dot + 1);
171 
172 
173                 StringBuffer buf = new StringBuffer();
174 
175                 String context = (mbean instanceof ObjectMBean)?makeName(((ObjectMBean)mbean).getObjectContextBasis()):null;
176                 if (context==null && pname!=null)
177                     context=pname.getKeyProperty("context");
178                                 
179                 if (context != null && context.length()>1)
180                     buf.append("context=").append(context).append(",");
181                 
182                 buf.append("type=").append(type);
183 
184                 String name = (mbean instanceof ObjectMBean)?makeName(((ObjectMBean)mbean).getObjectNameBasis()):context;
185                 if (name != null && name.length()>1)
186                     buf.append(",").append("name=").append(name);
187 
188                 String basis = buf.toString();
189                 Integer count = _unique.get(basis);
190                 count = count == null ? 0 : 1 + count;
191                 _unique.put(basis, count);
192 
193                 oname = ObjectName.getInstance(domain + ":" + basis + ",id=" + count);
194             }
195 
196             ObjectInstance oinstance = _mbeanServer.registerMBean(mbean, oname);
197             LOG.debug("Registered {}", oinstance.getObjectName());
198             _beans.put(obj, oinstance.getObjectName());
199 
200         }
201         catch (Exception e)
202         {
203             LOG.warn("bean: " + obj, e);
204         }
205     }
206 
207     @Override
208     public void beanRemoved(Container parent, Object obj)
209     {
210         LOG.debug("beanRemoved {}",obj);
211         ObjectName bean = _beans.remove(obj);
212 
213         if (bean != null)
214         {
215             try
216             {
217                 _mbeanServer.unregisterMBean(bean);
218                 LOG.debug("Unregistered {}", bean);
219             }
220             catch (javax.management.InstanceNotFoundException e)
221             {
222                 LOG.ignore(e);
223             }
224             catch (Exception e)
225             {
226                 LOG.warn(e);
227             }
228         }
229     }
230 
231     /**
232      * @param basis name to strip of special characters.
233      * @return normalized name
234      */
235     public String makeName(String basis)
236     {
237         if (basis==null)
238             return basis;
239         return basis.replace(':', '_').replace('*', '_').replace('?', '_').replace('=', '_').replace(',', '_').replace(' ', '_');
240     }
241 
242     @Override
243     public void dump(Appendable out, String indent) throws IOException
244     {
245         ContainerLifeCycle.dumpObject(out,this);
246         ContainerLifeCycle.dump(out, indent, _beans.entrySet());
247     }
248 
249     @Override
250     public String dump()
251     {
252         return ContainerLifeCycle.dump(this);
253     }
254 
255     public void destroy()
256     {
257         for (ObjectName oname : _beans.values())
258             if (oname!=null)
259             {
260                 try
261                 {
262                     _mbeanServer.unregisterMBean(oname);
263                 }
264                 catch (MBeanRegistrationException | InstanceNotFoundException e)
265                 {
266                     LOG.warn(e);
267                 }
268             }
269     }
270 }