1   //========================================================================
2   //Copyright 2005 Mort Bay Consulting Pty. Ltd.
3   //------------------------------------------------------------------------
4   //Licensed under the Apache License, Version 2.0 (the "License");
5   //you may not use this file except in compliance with the License.
6   //You may obtain a copy of the License at
7   //http://www.apache.org/licenses/LICENSE-2.0
8   //Unless required by applicable law or agreed to in writing, software
9   //distributed under the License is distributed on an "AS IS" BASIS,
10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  //See the License for the specific language governing permissions and
12  //limitations under the License.
13  //========================================================================
14  
15  package org.mortbay.management;
16  
17  import java.net.URL;
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.WeakHashMap;
24  
25  import javax.management.Attribute;
26  import javax.management.MBeanServer;
27  import javax.management.ObjectInstance;
28  import javax.management.ObjectName;
29  import javax.management.loading.PrivateMLet;
30  
31  import org.mortbay.component.AbstractLifeCycle;
32  import org.mortbay.component.Container;
33  import org.mortbay.component.Container.Relationship;
34  import org.mortbay.log.Log;
35  import org.mortbay.log.Logger;
36  import org.mortbay.util.MultiMap;
37  import org.mortbay.util.TypeUtil;
38  
39  public class MBeanContainer extends AbstractLifeCycle implements Container.Listener
40  {
41      private final MBeanServer _server;
42      private final WeakHashMap _beans = new WeakHashMap();
43      private final HashMap _unique = new HashMap();
44      private String _domain = null;
45      private MultiMap _relations = new MultiMap();
46      
47  
48      public synchronized ObjectName findMBean(Object object)
49      {
50          ObjectName bean = (ObjectName)_beans.get(object);
51          return bean==null?null:bean; 
52      }
53  
54      public synchronized Object findBean(ObjectName oname)
55      {
56          for (Iterator iter = _beans.entrySet().iterator(); iter.hasNext();)
57          {
58              Map.Entry entry = (Map.Entry) iter.next();
59              ObjectName bean = (ObjectName)entry.getValue();
60              if (bean.equals(oname))
61                  return entry.getKey();
62          }
63          return null;
64      }
65  
66      public MBeanContainer(MBeanServer server)
67      {
68          this._server = server;
69      }
70      
71      public MBeanServer getMBeanServer()
72      {
73          return _server;
74      }
75      
76      public void setDomain (String domain)
77      {
78          _domain =domain;
79      }
80      
81      public String getDomain()
82      {
83          return _domain;
84      }
85      
86      public void doStart()
87      {
88      }
89  
90      public synchronized void add(Relationship relationship)
91      {   
92          ObjectName parent=(ObjectName)_beans.get(relationship.getParent());
93          if (parent==null)
94          {
95              addBean(relationship.getParent());
96              parent=(ObjectName)_beans.get(relationship.getParent());
97          }
98          
99          ObjectName child=(ObjectName)_beans.get(relationship.getChild());
100         if (child==null)
101         {
102             addBean(relationship.getChild());
103             child=(ObjectName)_beans.get(relationship.getChild());
104         }
105         
106         if (parent!=null && child!=null)
107             _relations.add(parent,relationship);
108         
109         
110     }
111 
112     public synchronized void remove(Relationship relationship)
113     {
114         ObjectName parent=(ObjectName)_beans.get(relationship.getParent());
115         ObjectName child=(ObjectName)_beans.get(relationship.getChild());
116         if (parent!=null && child!=null)
117             _relations.removeValue(parent,relationship);
118     }
119 
120     public synchronized void removeBean(Object obj)
121     {
122         ObjectName bean=(ObjectName)_beans.remove(obj);
123 
124         if (bean!=null)
125         {
126             List r=_relations.getValues(bean);
127             if (r!=null && r.size()>0)
128             {
129                 Log.debug("Unregister {}", r);
130                 Iterator iter = new ArrayList(r).iterator();
131                 while (iter.hasNext())
132                 {
133                     Relationship rel = (Relationship)iter.next();
134                     rel.getContainer().update(rel.getParent(),rel.getChild(),null,rel.getRelationship(),true);
135                 }
136             }
137             
138             try
139             {
140                 _server.unregisterMBean(bean);
141                 Log.debug("Unregistered {}", bean);
142             }
143             catch (javax.management.InstanceNotFoundException e)
144             {
145                 Log.ignore(e);
146             }
147             catch (Exception e)
148             {
149                 Log.warn(e);
150             }
151         }
152     }
153     
154     public synchronized void addBean(Object obj)
155     {
156         try
157         {
158             if (obj == null || _beans.containsKey(obj))
159                 return;
160             
161             Object mbean = ObjectMBean.mbeanFor(obj);
162             if (mbean == null)
163                 return;
164 
165             ObjectName oname = null;
166             if (mbean instanceof ObjectMBean)
167             {
168                 ((ObjectMBean) mbean).setMBeanContainer(this);
169                 oname = ((ObjectMBean)mbean).getObjectName();
170             }
171             
172             //no override mbean object name, so make a generic one
173             if (oname == null)
174             {
175                 String type=obj.getClass().getName().toLowerCase();
176                 int dot = type.lastIndexOf('.');
177                 if (dot >= 0)
178                     type = type.substring(dot + 1);
179                 
180                 String name=null;
181                 if (mbean instanceof ObjectMBean)
182                 {
183                     name = ((ObjectMBean)mbean).getObjectNameBasis();
184                     if (name!=null)
185                     {
186                         name=name.replace('\\','/');
187                         if (name.endsWith("/"))
188                             name=name.substring(0,name.length()-1);
189 
190                         int slash=name.lastIndexOf('/',name.length()-1);
191                         if (slash>0)
192                             name=name.substring(slash+1);
193                         dot=name.lastIndexOf('.');
194                         if (dot>0)
195                             name=name.substring(0,dot);
196 
197                         name=name.replace(':','_').replace('*','_').replace('?','_').replace('=','_').replace(',','_').replace(' ','_');
198                     }
199                 }
200                 
201                 String basis=(name!=null&&name.length()>1)?("type="+type+",name="+name):("type="+type);
202                 
203                 Integer count = (Integer) _unique.get(basis);
204                 count = TypeUtil.newInteger(count == null ? 0 : (1 + count.intValue()));
205                 _unique.put(basis, count);
206 
207                 //if no explicit domain, create one
208                 String domain = _domain;
209                 if (domain==null)
210                     domain = obj.getClass().getPackage().getName();
211 
212                 oname = ObjectName.getInstance(domain+":"+basis+",id="+count);
213             }
214             
215             ObjectInstance oinstance = _server.registerMBean(mbean, oname);
216             Log.debug("Registered {}" , oinstance.getObjectName());
217             _beans.put(obj, oinstance.getObjectName());
218 
219         }
220         catch (Exception e)
221         {
222             Log.warn("bean: "+obj,e);
223         }
224     }
225     
226     public void doStop()
227     {
228         while (_beans.size()>0)
229             removeBean(_beans.keySet().iterator().next());
230     }
231     
232     private class ShutdownHook extends Thread
233     {
234         private final ObjectName mletName;
235         private final ObjectName adaptorName;
236         private final ObjectName processorName;
237 
238         public ShutdownHook(ObjectName mletName, ObjectName adaptorName, ObjectName processorName)
239         {
240             this.mletName = mletName;
241             this.adaptorName = adaptorName;
242             this.processorName = processorName;
243         }
244 
245         public void run()
246         {
247             halt();
248             unregister(processorName);
249             unregister(adaptorName);
250             unregister(mletName);
251         }
252 
253         private void halt()
254         {
255             try
256             {
257                 _server.invoke(adaptorName, "stop", null, null);
258             }
259             catch (Exception e)
260             {
261                 Log.warn(e);
262             }
263         }
264 
265         private void unregister(ObjectName objectName)
266         {
267             try
268             {
269                 _server.unregisterMBean(objectName);
270                 Log.debug("Unregistered " + objectName);
271             }
272             catch (Exception e)
273             {
274                 Log.warn(e);
275             }
276         }
277     }
278     
279 }