View Javadoc

1   // ========================================================================
2   // Copyright (c) 2005-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.jmx;
15  
16  import java.util.ArrayList;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Set;
22  import java.util.WeakHashMap;
23  import javax.management.MBeanServer;
24  import javax.management.ObjectInstance;
25  import javax.management.ObjectName;
26  
27  import org.eclipse.jetty.util.MultiMap;
28  import org.eclipse.jetty.util.component.AbstractLifeCycle;
29  import org.eclipse.jetty.util.component.Container;
30  import org.eclipse.jetty.util.component.Container.Relationship;
31  import org.eclipse.jetty.util.log.Log;
32  import org.eclipse.jetty.util.thread.ShutdownThread;
33  
34  
35  /* ------------------------------------------------------------ */
36  /**
37   * Container class for the MBean instances
38   */
39  public class MBeanContainer extends AbstractLifeCycle implements Container.Listener
40  {
41      private final MBeanServer _server;
42      private final WeakHashMap<Object, ObjectName> _beans = new WeakHashMap<Object, ObjectName>();
43      private final HashMap<String, Integer> _unique = new HashMap<String, Integer>();
44      private final MultiMap<ObjectName> _relations = new MultiMap<ObjectName>();
45      private String _domain = null;
46  
47      /* ------------------------------------------------------------ */
48      /**
49       * Lookup an object name by instance
50       *
51       * @param object instance for which object name is looked up
52       * @return object name associated with specified instance, or null if not found
53       */
54      public synchronized ObjectName findMBean(Object object)
55      {
56          ObjectName bean = (ObjectName)_beans.get(object);
57          return bean==null?null:bean;
58      }
59  
60      /* ------------------------------------------------------------ */
61      /**
62       * Lookup an instance by object name
63       *
64       * @param oname object name of instance
65       * @return instance associated with specified object name, or null if not found
66       */
67      public synchronized Object findBean(ObjectName oname)
68      {
69          for (Map.Entry<Object, ObjectName> entry : _beans.entrySet())
70          {
71              ObjectName bean = (ObjectName)entry.getValue();
72              if (bean.equals(oname))
73                  return entry.getKey();
74          }
75          return null;
76      }
77  
78      /* ------------------------------------------------------------ */
79      /**
80       * Constructs MBeanContainer
81       *
82       * @param server instance of MBeanServer for use by container
83       */
84      public MBeanContainer(MBeanServer server)
85      {
86          _server = server;
87  
88          try
89          {
90              start();
91          }
92          catch (Exception e)
93          {
94              Log.ignore(e);
95          }
96      }
97  
98      /* ------------------------------------------------------------ */
99      /**
100      * Retrieve instance of MBeanServer used by container
101      *
102      * @return instance of MBeanServer
103      */
104     public MBeanServer getMBeanServer()
105     {
106         return _server;
107     }
108 
109     /* ------------------------------------------------------------ */
110     /**
111      * Set domain to be used to add MBeans
112      *
113      * @param domain domain name
114      */
115     public void setDomain (String domain)
116     {
117         _domain = domain;
118     }
119 
120     /* ------------------------------------------------------------ */
121     /**
122      * Retrieve domain name used to add MBeans
123      *
124      * @return domain name
125      */
126     public String getDomain()
127     {
128         return _domain;
129     }
130 
131     /* ------------------------------------------------------------ */
132     /**
133      * Implementation of Container.Listener interface
134      *
135      * @see org.eclipse.jetty.util.component.Container.Listener#add(org.eclipse.jetty.util.component.Container.Relationship)
136      */
137     public synchronized void add(Relationship relationship)
138     {
139         ObjectName parent=(ObjectName)_beans.get(relationship.getParent());
140         if (parent==null)
141         {
142             addBean(relationship.getParent());
143             parent=(ObjectName)_beans.get(relationship.getParent());
144         }
145 
146         ObjectName child=(ObjectName)_beans.get(relationship.getChild());
147         if (child==null)
148         {
149             addBean(relationship.getChild());
150             child=(ObjectName)_beans.get(relationship.getChild());
151         }
152 
153         if (parent!=null && child!=null)
154             _relations.add(parent,relationship);
155     }
156 
157     /* ------------------------------------------------------------ */
158     /**
159      * Implementation of Container.Listener interface
160      *
161      * @see org.eclipse.jetty.util.component.Container.Listener#remove(org.eclipse.jetty.util.component.Container.Relationship)
162      */
163     public synchronized void remove(Relationship relationship)
164     {
165         ObjectName parent=(ObjectName)_beans.get(relationship.getParent());
166         ObjectName child=(ObjectName)_beans.get(relationship.getChild());
167         if (parent!=null && child!=null)
168             _relations.removeValue(parent,relationship);
169     }
170 
171     /* ------------------------------------------------------------ */
172     /**
173      * Implementation of Container.Listener interface
174      *
175      * @see org.eclipse.jetty.util.component.Container.Listener#removeBean(java.lang.Object)
176      */
177     public synchronized void removeBean(Object obj)
178     {
179         ObjectName bean=(ObjectName)_beans.remove(obj);
180 
181         if (bean!=null)
182         {
183             List<Relationship> beanRelations = _relations.getValues(bean);
184             if (beanRelations!=null && beanRelations.size()>0)
185             {
186                 Log.debug("Unregister {}", beanRelations);
187                 List<Relationship> removeList = new ArrayList<Relationship>(beanRelations);
188                 for (Relationship relation : removeList)
189                 {
190                     relation.getContainer().update(relation.getParent(),relation.getChild(),null,relation.getRelationship(),true);
191                 }
192             }
193 
194             try
195             {
196                 _server.unregisterMBean(bean);
197                 Log.debug("Unregistered {}", bean);
198             }
199             catch (javax.management.InstanceNotFoundException e)
200             {
201                 Log.ignore(e);
202             }
203             catch (Exception e)
204             {
205                 Log.warn(e);
206             }
207         }
208     }
209 
210     /* ------------------------------------------------------------ */
211     /**
212      * Implementation of Container.Listener interface
213      *
214      * @see org.eclipse.jetty.util.component.Container.Listener#addBean(java.lang.Object)
215      */
216     public synchronized void addBean(Object obj)
217     {
218         try
219         {
220             if (obj == null || _beans.containsKey(obj))
221                 return;
222 
223             Object mbean = ObjectMBean.mbeanFor(obj);
224             if (mbean == null)
225                 return;
226 
227             ObjectName oname = null;
228             if (mbean instanceof ObjectMBean)
229             {
230                 ((ObjectMBean) mbean).setMBeanContainer(this);
231                 oname = ((ObjectMBean)mbean).getObjectName();
232             }
233 
234             //no override mbean object name, so make a generic one
235             if (oname == null)
236             {
237                 String type=obj.getClass().getName().toLowerCase();
238                 int dot = type.lastIndexOf('.');
239                 if (dot >= 0)
240                     type = type.substring(dot + 1);
241 
242                 String name=null;
243                 if (mbean instanceof ObjectMBean)
244                 {
245                     name = ((ObjectMBean)mbean).getObjectNameBasis();
246                     if (name!=null)
247                     {
248                         name=name.replace('\\','/');
249                         if (name.endsWith("/"))
250                             name=name.substring(0,name.length()-1);
251 
252                         int slash=name.lastIndexOf('/',name.length()-1);
253                         if (slash>0)
254                             name=name.substring(slash+1);
255                         dot=name.lastIndexOf('.');
256                         if (dot>0)
257                             name=name.substring(0,dot);
258 
259                         name=name.replace(':','_').replace('*','_').replace('?','_').replace('=','_').replace(',','_').replace(' ','_');
260                     }
261                 }
262 
263                 String basis=(name!=null&&name.length()>1)?("type="+type+",name="+name):("type="+type);
264 
265                 Integer count = (Integer) _unique.get(basis);
266                 count = count == null ? 0 : 1 + count;
267                 _unique.put(basis, count);
268 
269                 //if no explicit domain, create one
270                 String domain = _domain;
271                 if (domain==null)
272                     domain = obj.getClass().getPackage().getName();
273 
274                 oname = ObjectName.getInstance(domain+":"+basis+",id="+count);
275             }
276 
277             ObjectInstance oinstance = _server.registerMBean(mbean, oname);
278             Log.debug("Registered {}" , oinstance.getObjectName());
279             _beans.put(obj, oinstance.getObjectName());
280 
281         }
282         catch (Exception e)
283         {
284             Log.warn("bean: "+obj,e);
285         }
286     }
287 
288     /* ------------------------------------------------------------ */
289     /**
290      * Perform actions needed to start lifecycle
291      *
292      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
293      */
294     public void doStart()
295     {
296         ShutdownThread.register(this);
297     }
298 
299     /* ------------------------------------------------------------ */
300     /**
301      * Perform actions needed to stop lifecycle
302      *
303      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
304      */
305     public void doStop()
306     {
307         Set<Object> removeSet = new HashSet<Object>(_beans.keySet());
308         for (Object removeObj : removeSet)
309         {
310             removeBean(removeObj);
311         }
312     }
313 }