User: starksm
Date: 01/04/03 19:43:22
Modified: src/docs howtombeans.xml jbossdocs.xml
Log:
Set title to JBoss 2.1+ documentation
Add simple MBean examples to howtombeans.xml
Revision Changes Path
1.4 +249 -4 manual/src/docs/howtombeans.xml
Index: howtombeans.xml
===================================================================
RCS file: /cvsroot/jboss/manual/src/docs/howtombeans.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- howtombeans.xml 2001/04/02 23:30:37 1.3
+++ howtombeans.xml 2001/04/04 02:43:21 1.4
@@ -1,8 +1,7 @@
<?xml version = "1.0" encoding = "UTF-8"?>
<section id = "howto.mbeans">
<title>How to Integrate Custom Services via MBeans</title>
- <para>Author:
- <author>
+ <para>Author:<author>
<firstname>Scott</firstname>
<surname>Stark</surname>
</author>
@@ -40,11 +39,11 @@
<para>JBoss manages dependencies between MBeans via the
org.jboss.util.ServiceControl custom MBean. . The ServiceControl MBean is also loaded
by the JMX MLet on JBoss startup. It implements the
javax.management.NotificationListener interface to receive
AttributeChangeNotification, MBeanServerNotification.REGISTRATION_NOTIFICATION and
MBeanServerNotification.UNREGISTRATION_NOTIFICATION JMX events.
AttributeChangeNotification are simply logged to the JBoss server log. The
REGISTRATION_NOTIFICATION and UNREGISTRATION_NOTIFICATION are used to determine which
MBeans are candidate JBoss service MBeans. The order of MBean registration is used as
the order of service initialization and startup. The ServiceControl MBean has four key
methods: init, start, stop and destroy.</para>
<section>
<title>The init Method</title>
- <para>The ServiceControl <function>init</function>
method is called by the JBoss server main entry point after the jboss.jcml
configuration has been loaded. The process of loading the jboss.jcml file will have
caused the names of all loaded MBeans to have been registered with the ServiceControl
MBean due to the registration events posted by the MBeanServer. The
<function>init</function> method makes a copy of curent list of MBean names and then
proceeds to invoke the <function>init</function> method on each MBean. If successful,
the ServiceControl MBean then registers as an NotificationListener on the MBean's name
to receive AttributeChangeNotification from the MBean. The order of initialization is
the order of registration which is the same as the ordering of mbean entries in the
jboss.jcml file.</para>
+ <para>The ServiceControl <function>init</function>
method is called by the JBoss server main entry point after the jboss.jcml
configuration has been loaded. The process of loading the jboss.jcml file will have
caused the names of all loaded MBeans to have been registered with the ServiceControl
MBean due to the registration events posted by the MBeanServer. The
<function>init</function> method makes a copy of curent list of MBean names and then
proceeds to invoke the <function>init</function> method on each MBean. If successful,
the ServiceControl MBean then registers as an NotificationListener on the MBean's name
to receive AttributeChangeNotification from the MBean. The order of initialization is
the order of registration which is the same as the ordering of mbean entries in the
jboss.jcml file. When an MBean's <function>init</function> method is called, all
MBeans that were registered ahead of it have also had their <function>init</function>
method invoked. This gives an MBean an opportunity to check that required MBeans or
resources exist. The MBean typically cannot utilize other MBean services at this point
as most JBoss MBean services do not become fully functional until they have been
started.</para>
</section>
<section>
<title>The start Method</title>
- <para>The ServiceControl <function>start</function>
method is called by the JBoss server main entry point after the
<function>init</function> method. The <function>start</function> method makes a copy
of curent list of MBean names and then proceeds to invoke the
<function>start</function> method on each MBean.</para>
+ <para>The ServiceControl <function>start</function>
method is called by the JBoss server main entry point after all MBeans have been
<function>init</function>d. The <function>start</function> method makes a copy of
curent list of MBean names and then proceeds to invoke the <function>start</function>
method on each MBean. When an MBean's <function>start</function> method is called, all
MBeans that were registered ahead of it have also had their <function>start</function>
method invoked. It is within the <function>start</function> method that signals an
MBean service to become fully operational.</para>
</section>
<section>
<title>The stop Method</title>
@@ -71,5 +70,251 @@
</listitem>
</itemizedlist>
<para>Which approach you choose depends on whether or not you want to
be associated with JBoss specific code. If you don't, then you would use the first
approach. If you don't mind, then the simplest approach is to have your MBean
interface extend from org.jboss.util.ServiceMBean and your MBean implementation class
extend from the abstract org.jboss.util.ServiceMBeanSupport class. This class
implements the org.jboss.util.ServiceMBean interface except for the <function>String
getName()</function> method. ServiceMBeanSupport provides implementations of the init,
start, stop and destroy methods that integrate logging and JBoss service state
management. Each method delegates any subclass specific work to initService,
startService, stopService, and destroyService methods respectively. When subclassing
ServiceMBeanSupport you would override one or more of the initService, startService,
stopService, and destroyService methods in addition to getName as required.</para>
+ </section>
+ <section>
+ <title>Examples</title>
+ <para>This section uses a simple MBean that binds a HashMap into the
JBoss JNDI namespace at a location determined by its JndiName attribute. Because the
MBean uses JNDI it depdends on the JBoss naming service MBean and therefore must use
the JBoss MBean service pattern to be notified of when the naming service is
available.</para>
+ <section>
+ <title>JNDIMap MBean That Implements Service Methods</title>
+ <para>
+ <xref linkend = "howto.mbeans.Service"/> gives the
MBean interface for the JNDIMap MBean that incorporates that Service interface methods
that it needs to startup correctly. The interface includes the Service
<function>start</function> method to be informed when all required services have been
started and the <function>stop</function> method to clean up the service.</para>
+ <figure id = "howto.mbeans.Service">
+ <title>JNDIMap MBean Interface and Implementation
Based On the Service Interface</title>
+ <programlisting>// The JNDIMap MBean interface
+import javax.naming.NamingException;
+
+public interface JNDIMapMBean
+{
+ public String getJndiName();
+ public void setJndiName(String jndiName) throws NamingException;
+ public void start() throws Exception;
+ public void stop() throws Exception;
+}</programlisting>
+ <programlisting>// The JNDIMap MBean
implementation<![CDATA[
+import java.io.InputStream;
+import java.util.HashMap;
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import org.jboss.naming.NonSerializableFactory;
+
+public class JNDIMap implements JNDIMapMBean
+{
+ private String jndiName;
+ private HashMap contextMap = new HashMap();
+ private boolean started;
+
+ public String getJndiName()
+ {
+ return jndiName;
+ }
+ public void setJndiName(String jndiName) throws NamingException
+ {
+ String oldName = this.jndiName;
+ this.jndiName = jndiName;
+ if( started )
+ {
+ unbind(oldName);
+ try
+ {
+ rebind();
+ }
+ catch(Exception e)
+ {
+ NamingException ne = new NamingException("Failed to update
jndiName");
+ ne.setRootCause(e);
+ throw ne;
+ }
+ }
+ }
+
+ public void start() throws Exception
+ {
+ started = true;
+ rebind();
+ }
+
+ public void stop()
+ {
+ started = false;
+ unbind(jndiName);
+ }
+
+ private static Context createContext(Context rootContext, Name name) throws
NamingException
+ {
+ Context subctx = rootContext;
+ for(int n = 0; n < name.size(); n ++)
+ {
+ String atom = name.get(n);
+ try
+ {
+ Object obj = subctx.lookup(atom);
+ subctx = (Context) obj;
+ }
+ catch(NamingException e)
+ { // No binding exists, create a subcontext
+ subctx = subctx.createSubcontext(atom);
+ }
+ }
+
+ return subctx;
+ }
+
+ private void rebind() throws NamingException
+ {
+ InitialContext rootCtx = new InitialContext();
+ // Get the parent context into which we are to bind
+ Name fullName = rootCtx.getNameParser("").parse(jndiName);
+ log.debug("fullName="+fullName);
+ Name parentName = fullName;
+ if( fullName.size() > 1 )
+ parentName = fullName.getPrefix(fullName.size()-1);
+ else
+ parentName = new CompositeName();
+ Context parentCtx = createContext(rootCtx, parentName);
+ Name atomName = fullName.getSuffix(fullName.size()-1);
+ String atom = atomName.get(0);
+ NonSerializableFactory.rebind(parentCtx, atom, contextMap);
+ }
+ private void unbind(String jndiName)
+ {
+ try
+ {
+ Context rootCtx = (Context) new InitialContext();
+ rootCtx.unbind(jndiName);
+ NonSerializableFactory.unbind(jndiName);
+ }
+ catch(NamingException e)
+ {
+ log.exception(e);
+ }
+ }
+}
+]]></programlisting>
+ </figure>
+ </section>
+ <section>
+ <title>JNDIMap MBean That Extends ServiceMBean</title>
+ <para>
+ <xref linkend = "howto.mbeans.ServiceMBean"/> gives
the MBean interface for the JNDIMap MBean that extends th ServiceMBean interface. The
implementation class then extends the ServiceMBeanSupport class and overrides the
<function>startService</function> method to be informed when all required services
have been started and the <function>stopService</function> method to clean up the
service. It also implements the abstract <function>getName</function> to return a
descriptive name for the MBean.</para>
+ <figure id = "howto.mbeans.ServiceMBean">
+ <title>JNDIMap MBean Interface and Implementation
Based On the ServiceMBean Interface and ServiceMBeanSupport Class</title>
+ <programlisting>// The JNDIMap MBean interface
+import javax.naming.NamingException;
+
+public interface JNDIMapMBean extends org.jboss.util.ServiceMBean
+{
+ public String getJndiName();
+ public void setJndiName(String jndiName) throws NamingException;
+}</programlisting>
+ <programlisting>// The JNDIMap MBean
implementation<![CDATA[
+import java.io.InputStream;
+import java.util.HashMap;
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import org.jboss.naming.NonSerializableFactory;
+
+public class JNDIMap extends org.jboss.util.ServiceMBeanSupport implements
JNDIMapMBean
+{
+ private String jndiName;
+ private HashMap contextMap = new HashMap();
+
+ public String getJndiName()
+ {
+ return jndiName;
+ }
+ public void setJndiName(String jndiName) throws NamingException
+ {
+ String oldName = this.jndiName;
+ this.jndiName = jndiName;
+ if( super.getState() == STARTED )
+ {
+ unbind(oldName);
+ try
+ {
+ rebind();
+ }
+ catch(Exception e)
+ {
+ NamingException ne = new NamingException("Failed to update
jndiName");
+ ne.setRootCause(e);
+ throw ne;
+ }
+ }
+ }
+
+ public String getName()
+ {
+ return "JNDIMap(" + jndiName + ")";
+ }
+
+ public void startService() throws Exception
+ {
+ rebind();
+ }
+
+ public void stopService()
+ {
+ unbind(jndiName);
+ }
+
+ private static Context createContext(Context rootContext, Name name) throws
NamingException
+ {
+ Context subctx = rootContext;
+ for(int n = 0; n < name.size(); n ++)
+ {
+ String atom = name.get(n);
+ try
+ {
+ Object obj = subctx.lookup(atom);
+ subctx = (Context) obj;
+ }
+ catch(NamingException e)
+ { // No binding exists, create a subcontext
+ subctx = subctx.createSubcontext(atom);
+ }
+ }
+
+ return subctx;
+ }
+
+ private void rebind() throws NamingException
+ {
+ InitialContext rootCtx = new InitialContext();
+ // Get the parent context into which we are to bind
+ Name fullName = rootCtx.getNameParser("").parse(jndiName);
+ log.debug("fullName="+fullName);
+ Name parentName = fullName;
+ if( fullName.size() > 1 )
+ parentName = fullName.getPrefix(fullName.size()-1);
+ else
+ parentName = new CompositeName();
+ Context parentCtx = createContext(rootCtx, parentName);
+ Name atomName = fullName.getSuffix(fullName.size()-1);
+ String atom = atomName.get(0);
+ NonSerializableFactory.rebind(parentCtx, atom, contextMap);
+ }
+ private void unbind(String jndiName)
+ {
+ try
+ {
+ Context rootCtx = (Context) new InitialContext();
+ rootCtx.unbind(jndiName);
+ NonSerializableFactory.unbind(jndiName);
+ }
+ catch(NamingException e)
+ {
+ log.exception(e);
+ }
+ }
+}
+]]></programlisting>
+ </figure>
+ </section>
</section>
</section>
1.14 +2 -2 manual/src/docs/jbossdocs.xml
Index: jbossdocs.xml
===================================================================
RCS file: /cvsroot/jboss/manual/src/docs/jbossdocs.xml,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- jbossdocs.xml 2001/04/03 16:47:32 1.13
+++ jbossdocs.xml 2001/04/04 02:43:21 1.14
@@ -25,14 +25,14 @@
<!ENTITY howtojpda.xml SYSTEM "howtojpda.xml">
<!ENTITY howtomssql.xml SYSTEM "howtomssql.xml">
<!ENTITY howtojetty.xml SYSTEM "howtojetty.xml">
- <!ENTITY howtoverifier.xml SYSTEM "howtoverifier.xml">
+ <!ENTITY howtoverifier.xml SYSTEM "howtoverifier.xml">
<!ENTITY howtombeans.xml SYSTEM "howtombeans.xml">
<!ENTITY jbosssx.xml SYSTEM "jbosssx.xml">
<!ENTITY howtovisualagedebug.xml SYSTEM "howtovisualagedebug.xml">
]>
<book>
<bookinfo>
- <title>JBoss 2.0 documentation</title>
+ <title>JBoss 2.1+ documentation</title>
<copyright>
<year>2000</year>
<year>2001</year>
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development