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