KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > system > ServiceMBeanSupport


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.system;
23
24 import javax.management.AttributeChangeNotification JavaDoc;
25 import javax.management.JMException JavaDoc;
26 import javax.management.MBeanInfo JavaDoc;
27 import javax.management.MBeanOperationInfo JavaDoc;
28 import javax.management.MBeanRegistration JavaDoc;
29 import javax.management.MBeanServer JavaDoc;
30 import javax.management.MalformedObjectNameException JavaDoc;
31 import javax.management.ObjectName JavaDoc;
32
33 import org.jboss.deployment.DeploymentInfo;
34 import org.jboss.deployment.SARDeployerMBean;
35 import org.jboss.logging.Logger;
36 import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
37
38 /**
39  * An abstract base class JBoss services can subclass to implement a
40  * service that conforms to the ServiceMBean interface. Subclasses must
41  * override {@link #getName} method and should override
42  * {@link #startService}, and {@link #stopService} as approriate.
43  *
44  * @see ServiceMBean
45  *
46  * @author <a HREF="mailto:rickard.oberg@telkel.com">Rickard Öberg</a>
47  * @author Scott.Stark@jboss.org
48  * @author <a HREF="mailto:andreas@jboss.org">Andreas Schaefer</a>
49  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
50  * @version $Revision: 57108 $
51  */

52 public class ServiceMBeanSupport
53    extends JBossNotificationBroadcasterSupport
54    implements ServiceMBean, MBeanRegistration JavaDoc
55 {
56    /** The signature for service controller operations */
57    public static final String JavaDoc[] SERVICE_CONTROLLER_SIG = new String JavaDoc[] { ObjectName JavaDoc.class.getName() };
58    
59    /**
60     * The instance logger for the service. Not using a class logger
61     * because we want to dynamically obtain the logger name from
62     * concreate sub-classes.
63     */

64    protected Logger log;
65    
66    /** The MBeanServer which we have been register with. */
67    protected MBeanServer JavaDoc server;
68
69    /** The object name which we are registsred under. */
70    protected ObjectName JavaDoc serviceName;
71
72    /** The current state this service is in. */
73    private int state = UNREGISTERED;
74
75    /** For backwards compatibility */
76    private boolean isJBossInternalLifecycleExposed = false;
77    
78    /**
79     * Construct a <t>ServiceMBeanSupport</tt>.
80     *
81     * <p>Sets up logging.
82     */

83    public ServiceMBeanSupport()
84    {
85       // can not call this(Class) because we need to call getClass()
86
this.log = Logger.getLogger(getClass().getName());
87       log.trace("Constructing");
88    }
89
90    /**
91     * Construct a <t>ServiceMBeanSupport</tt>.
92     *
93     * <p>Sets up logging.
94     *
95     * @param type The class type to determine category name from.
96     */

97    public ServiceMBeanSupport(final Class JavaDoc type)
98    {
99       this(type.getName());
100    }
101    
102    /**
103     * Construct a <t>ServiceMBeanSupport</tt>.
104     *
105     * <p>Sets up logging.
106     *
107     * @param category The logger category name.
108     */

109    public ServiceMBeanSupport(final String JavaDoc category)
110    {
111       this(Logger.getLogger(category));
112    }
113
114    /**
115     * Construct a <t>ServiceMBeanSupport</tt>.
116     *
117     * @param log The logger to use.
118     */

119    public ServiceMBeanSupport(final Logger log)
120    {
121       this.log = log;
122       log.trace("Constructing");
123    }
124
125    /**
126     * Use the short class name as the default for the service name.
127     */

128    public String JavaDoc getName()
129    {
130       // TODO: Check if this gets called often, if so cache this or remove if not used
131
// use the logger so we can better be used as a delegate instead of sub-class
132
return org.jboss.util.Classes.stripPackageName(log.getName());
133    }
134    
135    public ObjectName JavaDoc getServiceName()
136    {
137       return serviceName;
138    }
139
140    /**
141     * Provide access to the service DeploymentInfo. This is only available
142     * after the service has passed its create step.
143     *
144     * @return The service DeploymentInfo if found registered under the SARDeployer.
145     * @throws JMException - thrown on failure to invoke
146     * SARDeployer.getService(ObjectName)
147     */

148    public DeploymentInfo getDeploymentInfo()
149       throws JMException JavaDoc
150    {
151       Object JavaDoc[] args = {serviceName};
152       String JavaDoc[] sig = {serviceName.getClass().getName()};
153       DeploymentInfo sdi = (DeploymentInfo) server.invoke(SARDeployerMBean.OBJECT_NAME,
154          "getService", args, sig);
155       return sdi;
156    }
157
158    public MBeanServer JavaDoc getServer()
159    {
160       return server;
161    }
162    
163    public int getState()
164    {
165       return state;
166    }
167    
168    public String JavaDoc getStateString()
169    {
170       return states[state];
171    }
172    
173    public Logger getLog()
174    {
175       return log;
176    }
177
178
179    ///////////////////////////////////////////////////////////////////////////
180
// State Mutators //
181
///////////////////////////////////////////////////////////////////////////
182

183    public void create() throws Exception JavaDoc
184    {
185       if (serviceName != null && isJBossInternalLifecycleExposed)
186          server.invoke(ServiceController.OBJECT_NAME, "create", new Object JavaDoc[] { serviceName }, SERVICE_CONTROLLER_SIG);
187       else
188          jbossInternalCreate();
189    }
190    
191    public void start() throws Exception JavaDoc
192    {
193       if (serviceName != null && isJBossInternalLifecycleExposed)
194          server.invoke(ServiceController.OBJECT_NAME, "start", new Object JavaDoc[] { serviceName }, SERVICE_CONTROLLER_SIG);
195       else
196          jbossInternalStart();
197    }
198    
199    public void stop()
200    {
201       try
202       {
203          if (serviceName != null && isJBossInternalLifecycleExposed)
204             server.invoke(ServiceController.OBJECT_NAME, "stop", new Object JavaDoc[] { serviceName }, SERVICE_CONTROLLER_SIG);
205          else
206             jbossInternalStop();
207       }
208       catch (Throwable JavaDoc t)
209       {
210          log.warn("Error in stop " + jbossInternalDescription(), t);
211       }
212    }
213    
214    public void destroy()
215    {
216       try
217       {
218          if (serviceName != null && isJBossInternalLifecycleExposed)
219             server.invoke(ServiceController.OBJECT_NAME, "destroy", new Object JavaDoc[] { serviceName }, SERVICE_CONTROLLER_SIG);
220          else
221             jbossInternalDestroy();
222       }
223       catch (Throwable JavaDoc t)
224       {
225          log.warn("Error in destroy " + jbossInternalDescription(), t);
226       }
227    }
228    
229    protected String JavaDoc jbossInternalDescription()
230    {
231       if (serviceName != null)
232          return serviceName.toString();
233       else
234          return getName();
235    }
236    
237    public void jbossInternalLifecycle(String JavaDoc method) throws Exception JavaDoc
238    {
239       if (method == null)
240          throw new IllegalArgumentException JavaDoc("Null method name");
241       
242       if (method.equals("create"))
243          jbossInternalCreate();
244       else if (method.equals("start"))
245          jbossInternalStart();
246       else if (method.equals("stop"))
247          jbossInternalStop();
248       else if (method.equals("destroy"))
249          jbossInternalDestroy();
250       else
251          throw new IllegalArgumentException JavaDoc("Unknown lifecyle method " + method);
252    }
253    
254    protected void jbossInternalCreate() throws Exception JavaDoc
255    {
256       log.debug("Creating " + jbossInternalDescription());
257       
258       try
259       {
260          createService();
261          state = CREATED;
262       }
263       catch (Exception JavaDoc e)
264       {
265          log.debug("Initialization failed " + jbossInternalDescription(), e);
266          throw e;
267       }
268       
269       log.debug("Created " + jbossInternalDescription());
270    }
271
272    protected void jbossInternalStart() throws Exception JavaDoc
273    {
274       if (state == STARTING || state == STARTED || state == STOPPING)
275          return;
276
277       if (state != CREATED && state != STOPPED && state != FAILED)
278       {
279          log.debug("Start requested before create, calling create now");
280          create();
281       }
282       
283       state = STARTING;
284       sendStateChangeNotification(STOPPED, STARTING, getName() + " starting", null);
285       log.debug("Starting " + jbossInternalDescription());
286
287       try
288       {
289          startService();
290       }
291       catch (Exception JavaDoc e)
292       {
293          state = FAILED;
294          sendStateChangeNotification(STARTING, FAILED, getName() + " failed", e);
295          log.debug("Starting failed " + jbossInternalDescription(), e);
296          throw e;
297       }
298
299       state = STARTED;
300       sendStateChangeNotification(STARTING, STARTED, getName() + " started", null);
301       log.debug("Started " + jbossInternalDescription());
302    }
303    
304    protected void jbossInternalStop()
305    {
306       if (state != STARTED)
307          return;
308       
309       state = STOPPING;
310       sendStateChangeNotification(STARTED, STOPPING, getName() + " stopping", null);
311       log.debug("Stopping " + jbossInternalDescription());
312
313       try
314       {
315          stopService();
316       }
317       catch (Throwable JavaDoc e)
318       {
319          state = FAILED;
320          sendStateChangeNotification(STOPPING, FAILED, getName() + " failed", e);
321          log.warn("Stopping failed " + jbossInternalDescription(), e);
322          return;
323       }
324       
325       state = STOPPED;
326       sendStateChangeNotification(STOPPING, STOPPED, getName() + " stopped", null);
327       log.debug("Stopped " + jbossInternalDescription());
328    }
329
330    protected void jbossInternalDestroy()
331    {
332       if (state == DESTROYED)
333          return;
334       
335       if (state == STARTED)
336       {
337          log.debug("Destroy requested before stop, calling stop now");
338          stop();
339       }
340       
341       log.debug("Destroying " + jbossInternalDescription());
342       
343       try
344       {
345          destroyService();
346       }
347       catch (Throwable JavaDoc t)
348       {
349          log.warn("Destroying failed " + jbossInternalDescription(), t);
350       }
351       state = DESTROYED;
352       log.debug("Destroyed " + jbossInternalDescription());
353    }
354
355
356    ///////////////////////////////////////////////////////////////////////////
357
// JMX Hooks //
358
///////////////////////////////////////////////////////////////////////////
359

360    /**
361     * Callback method of {@link MBeanRegistration}
362     * before the MBean is registered at the JMX Agent.
363     *
364     * <p>
365     * <b>Attention</b>: Always call this method when you overwrite it in a subclass
366     * because it saves the Object Name of the MBean.
367     *
368     * @param server Reference to the JMX Agent this MBean is registered on
369     * @param name Name specified by the creator of the MBean. Note that you can
370     * overwrite it when the given ObjectName is null otherwise the
371     * change is discarded (maybe a bug in JMX-RI).
372     */

373    public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server, ObjectName JavaDoc name)
374       throws Exception JavaDoc
375    {
376       this.server = server;
377
378       serviceName = getObjectName(server, name);
379       
380       return serviceName;
381    }
382    
383    public void postRegister(Boolean JavaDoc registrationDone)
384    {
385       if (!registrationDone.booleanValue())
386       {
387          log.info( "Registration is not done -> stop" );
388          stop();
389       }
390       else
391       {
392          state = REGISTERED;
393          // This is for backwards compatibility - see whether jbossInternalLifecycle is exposed
394
try
395          {
396             MBeanInfo JavaDoc info = server.getMBeanInfo(serviceName);
397             MBeanOperationInfo JavaDoc[] ops = info.getOperations();
398             for (int i = 0; i < ops.length; ++i)
399             {
400                if (ops[i] != null && ServiceController.JBOSS_INTERNAL_LIFECYCLE.equals(ops[i].getName()))
401                {
402                   isJBossInternalLifecycleExposed = true;
403                   break;
404                }
405             }
406          }
407          catch (Throwable JavaDoc t)
408          {
409             log.warn("Unexcepted error accessing MBeanInfo for " + serviceName, t);
410          }
411       }
412    }
413
414    public void preDeregister() throws Exception JavaDoc
415    {
416    }
417    
418    public void postDeregister()
419    {
420       server = null;
421       serviceName = null;
422       state = UNREGISTERED;
423    }
424
425    /**
426     * The <code>getNextNotificationSequenceNumber</code> method returns
427     * the next sequence number for use in notifications.
428     *
429     * @return a <code>long</code> value
430     */

431    protected long getNextNotificationSequenceNumber()
432    {
433       return nextNotificationSequenceNumber();
434    }
435
436
437    ///////////////////////////////////////////////////////////////////////////
438
// Concrete Service Overrides //
439
///////////////////////////////////////////////////////////////////////////
440

441    /**
442     * Sub-classes should override this method if they only need to set their
443     * object name during MBean pre-registration.
444     */

445    protected ObjectName JavaDoc getObjectName(MBeanServer JavaDoc server, ObjectName JavaDoc name)
446       throws MalformedObjectNameException JavaDoc
447    {
448       return name;
449    }
450
451    /**
452     * Sub-classes should override this method to provide
453     * custum 'create' logic.
454     *
455     * <p>This method is empty, and is provided for convenience
456     * when concrete service classes do not need to perform
457     * anything specific for this state change.
458     */

459    protected void createService() throws Exception JavaDoc {}
460    
461    /**
462     * Sub-classes should override this method to provide
463     * custum 'start' logic.
464     *
465     * <p>This method is empty, and is provided for convenience
466     * when concrete service classes do not need to perform
467     * anything specific for this state change.
468     */

469    protected void startService() throws Exception JavaDoc {}
470    
471    /**
472     * Sub-classes should override this method to provide
473     * custum 'stop' logic.
474     *
475     * <p>This method is empty, and is provided for convenience
476     * when concrete service classes do not need to perform
477     * anything specific for this state change.
478     */

479    protected void stopService() throws Exception JavaDoc {}
480    
481    /**
482     * Sub-classes should override this method to provide
483     * custum 'destroy' logic.
484     *
485     * <p>This method is empty, and is provided for convenience
486     * when concrete service classes do not need to perform
487     * anything specific for this state change.
488     */

489    protected void destroyService() throws Exception JavaDoc {}
490    
491    // Private -------------------------------------------------------
492

493    /**
494     * Helper for sending out state change notifications
495     */

496    private void sendStateChangeNotification(int oldState, int newState, String JavaDoc msg, Throwable JavaDoc t)
497    {
498       long now = System.currentTimeMillis();
499       
500       AttributeChangeNotification JavaDoc stateChangeNotification = new AttributeChangeNotification JavaDoc(
501          this,
502          getNextNotificationSequenceNumber(), now, msg,
503          "State", "java.lang.Integer",
504          new Integer JavaDoc(oldState), new Integer JavaDoc(newState)
505          );
506       stateChangeNotification.setUserData(t);
507       
508       sendNotification(stateChangeNotification);
509    }
510 }
511
Popular Tags