This short Blog entry will take you through building a simple NetBeans
Plug-in that can be used to browse the contents of a JMS Queue Manager.
For the purpose of the Blog I will interface to the Java CAPS 6 Message
Server although the example should be flexible enough to work with any
Message Server assuming you have the appropriate interface. To interact
with the Java CAPS Message Server this Blog entry will be built arounf
the stcqueueviewer API but following on from this I have written the
entry "NetBeans
6.1 Monitoring based on the Management API" that will highlight how
we can modify it to use the Java CAPS Management API.
Contents
The Module implemented within this blog will create a simple Java CAPS 6 JMS Servers node that will be integrated into the NetBeans Services tab in a similar way to the existing Servers node. The module will allow the user to specify and connect to multiple Sun-SeeBeyond JMS Servers and the associated configuration will be stored within the NetBeans <userdir>/config/JMSServer directory. Once connected to the appropriate Java CAPS 6 JMS Manager the user will be able to view all the Queues and Topics that are available within that Server and then for each Queue or Topic the Messages that are currently available.
This simple implement will provide the reader with the ability to build a JMS Monitoring / Management system that is integrated into the NetBeans framework.

NetBeans provides a special Project Type that needs to be used to create and configure you module correctly. Therefore you will need to follow the Step below in order to create you JMS Message Server Browser Plug-in.

The meat of the module is based in its Java code and to successfully implement the functionality we will require the following distinct steps:
MsgServer.java
Queue.java
Topic.java
Msg.java
Creating
the NetBeans Interface
Now that we have created the access class required to retrieve the
Message Server information we need a framework within which this
information will be displayed. To achieve this we will add an addition
node to the Services Tab,
similar to the Servers node, that will contain a list of all JMS
Servers we want to connect to. The information for each of these
Messages servers will be store within a properties file below the
<UserDir>/config/JMSServers directory. BBy default the Server
Nodes will not connect to their specified JMS Message Server but
instead we will provide Connect / Disconnect Actions and a default
(Preferred Action) Double-Click that will connect to the Server. Once
connected tot he Server two specific Node types will be added to the
Server. One of these will represent a Queue whilst the other represents
a Topic. Again on these we will add a number of Actions and a Default
(PreferredAction) that opens a display component to list all the
messages on the Queue/Topic.
In this section we will examine the core java classes required to implement the NetBeans Module functionality and describe the key methods:
AllMsgServersNode.java
This Java Class extends the AbstractNode specifying what children will exist below the main node and uses the AllMsgServersChildren class to keep track of the list of child nodes. The Node takes care of things such as the context menu and associated actions.
AllMsgServersChildren.java
This class is responsible for keeping track of the list Message Servers that exists below the Root node. When first asked for the list it will read all msgserver*.properties files that exist below the <userdir>/config/JMSServer directory (previous created using Add Message Server) and asks the node implementation to keep track of the loaded properties files. This class extends the Children.keys class and therefore we do not need to explicitly keep track of the nodes. Instead we track the keys which represent the nodes. We define, within the implementation, how to create a node for each key.
OneMsgServerNode.java
This Java Class extends the AbstractNode specifying what children will exist below the AllMsgServersNode node and uses the OneMsgServerChildren class to keep track of the child nodes. The Node takes care of things such as the context menu and associated actions.
This class is responsible for keeping track of all the Queues and Topics that exist within the selected Message Server. When first asked for the list it will call the getQueues() and getTopics() methods for the associated MsgServer class and ask the node implementation to keep track of them. The class extends the Children.keys class and therefore does not need to explicitly keep track of the node. On returning from this call the keys associated with the node are of two types QueueInterface and TopicInterface and therefore when creating the nodes we will need to take this into account.
OneQueueNode.java / OneTopicNode.java
Essentially these classes are the same except one will deal with a specific Queue whilst the other deals with a specific Topic. These Java Classes provide the AbstractNode implementation for a single Queue or Topic and the constructor takes a QueueInterface or TopicInterface as the parameters. Because these nodes will never contain any sub-node the constructors call super(Children.LEAF) to indicate to the NetBeans framework that this is the case.
This class is used to display the Messages that reside on either a Queue or a Topic. To created this class, and its associated files, we will create a New Window Component within the project. When this is done NetBeans will generate the skeleton classes required and and example action that can be used to initiate the display of the component. Because we will be calling this from both the OneQueueNode and the OneTopicNode we will not be using the generated Action but rather taking the code and implementing the Inner class ViewMsgAction.
This will create a number of files and we will now modify the MsgListTopComponent.java to display the data correctly. I will not go into details on how to build the swing component because reviewing the code within NetBeans will show you the required code. In stead I will list the methods that were modified from those created by the New Windows Component call.
Within the OneQueueNode.java and the OneTopicNode.java the following Inner class will need to be created. This will define the ViewMsgAction that appears in the context menu.
AllMsgServersNotifier.java / OneMsgSeverNotifier.java
These Java classes manage routing events whenever their are changes to the appropriate nodes. The child node will register with the appropriate Notifier.
RefreshAllMsgServersAction.java / RefreshMsgServerAction.java
These Java classes provide Refresh actions to the AllMsgServersNode and OneMsgServerNode and appear as the "Refresh" option in the appropriate context menu. They force a refresh to occur updating the display of the information and refreshes the list of sub-nodes.
Creating
the Supporting Files
Once we have successfully coded the main files we must specify how we
would like our Module to impact the filesystem and what labels and text
we want to display the the user. The layer.xml file and the
Bundle.properties file are used for this.
Now that we have completed the module it is time to try it out. NetBeans provides the ability to test out a module without having to install it with the Development environment so we will use this to run the module and then when happy generate the NBM to be installed in the Development environment.
Resources
Keywords
Contents
- Module Description
- Creating a Module
- Coding The Module
- Compiling, Installing and running your Module
Module Description
The Module implemented within this blog will create a simple Java CAPS 6 JMS Servers node that will be integrated into the NetBeans Services tab in a similar way to the existing Servers node. The module will allow the user to specify and connect to multiple Sun-SeeBeyond JMS Servers and the associated configuration will be stored within the NetBeans <userdir>/config/JMSServer directory. Once connected to the appropriate Java CAPS 6 JMS Manager the user will be able to view all the Queues and Topics that are available within that Server and then for each Queue or Topic the Messages that are currently available.
This simple implement will provide the reader with the ability to build a JMS Monitoring / Management system that is integrated into the NetBeans framework.

Creating a Module Suite & Module
NetBeans provides a special Project Type that needs to be used to create and configure you module correctly. Therefore you will need to follow the Step below in order to create you JMS Message Server Browser Plug-in.
- Create a NetBeans Module Suite: File -> New Project ->NetBeans Modules -> Module Suite (Next)
- Create
a Plug-in Module: Right-click JMSBrowserSuite Modules -> New Module
(Next)
- In the Name Type JMSBrowser. Leave the Standalone Module Option selected (Next)
- In
the Basic Module Configuration Panel set the package name to
org.sun.aph.nbm.jmsbrowser.
Specify the location of the bundle and XML Layer file below com/sun/aph/nbm/jmsbrowser (Finish)
NetBeans will now create the JMSBrowser Project and is ready to edit.

- Create a new Jar Wrapper Module: Right-click JMSBrowserSuite Modules -> New Library (Next)
- Add
the following Jars to the wrapper (multi Select) and they can be found
in the <Java CAPS6 Root>/appserver/addons/stcms (Next)
- com.stc.jms.stcjms.jar
- com.stc.jms.stcqueueviewer
- jms.jar
- In the Name Type JMSBrowserSTCWrapper and leave all other fields to their default (Next)
- Change
the "Code Name Base" to com.stc.jms.wrapper and the Module Display Name
to JMS Browser STC Wrapper (Finish)
Module Dependencies
To facilitate the integration of the JMS Functionality into the Runtime Tab we will need to subclass several classes that belong to the NetBeans APIs. Each of these APIs needs to be defined as a project, module, dependency. In addition to this we will need to define the appropriate Sun SeeBeyond JMS Manager libraries as dependencies. This can be achieved through the Project Properties dialog box.- Right-click on the project and select properties and the Properties Dialog will open.
- Within the Dialog select Libraries and add the following dependencies:

Coding The Module
The meat of the module is based in its Java code and to successfully implement the functionality we will require the following distinct steps:
- Creating the JMS Message Server Interface
- Creating the NetBeans Interface
- Creating the Supporting
Files
Creating the JMS Message Server Interface
To access the JMS Message Server we will need to create a number of accessor classes. Although this specific tutorial is aimed at connecting to the Java CAPS 6 Sun-SeeBeyond Message Server the interaction is based on Interface Definitions and therefore could be extended to integrate with other JMS Message Servers. The classes and interfaces we will need to create are described below.| Class
/ Interface |
Description |
Methods |
|---|---|---|
| MsgServerInterface |
Defines the Methods required to
access a Message Server. |
|
| QueueInterface |
Defines the Methods required to
access queue information |
|
| TopicInterface |
Defines the Methods required to access topic information |
|
| MsgInterface |
Defines the Methods for
retrieving Message information |
|
| MsgServerFactory |
Factory class used to retrieve
the appropriate concrete MsgServer based on the supplied Server name.
At present it will always return the Sun-SeeBeyond Server. |
|
| MsgServer |
Represents a specific Message
Server that we will connect to. Contains all the appropriate
information host, port, username and password. Will control connection,
disconnect and access to the server. |
|
| Queue |
Java CAPS 6 specific
implementation of the JMS Queue |
|
| Topic |
Java CAPS 6 Specific
implementation for a JMS Topic |
|
| Msg |
Java CAPS 6 Specific
implementation of the MsgInterface |
|
MsgServer.java
- connect () : Takes the specified connection parameters (host, port, username and password) and connects to the JMS Server
- disconnect () : If the server is connected then disconnect.
- isConnected () : Check if we are currently connected to the Message Server.
- getQueues () : Returns a list of Queues, as QueueInterface, that exist on the Message Server.
- getTopics () : Returns a list of Topics, as TopicInterface, that exist on the Message Server.
- getQueueStatistics () : Get the Overall Queue Statistical information for a specified Queue.
- getTopicStatistics () : Get the overall Topic statistical information for the specified Topic.
- getQueueMessages () : Returns the messages on a specific queue as a List of MsgInterface.
- getTopicMessages () : Returns the messages on a specific Topic as a List of MsgInterface.
Queue.java
- getQName () : Returns the name of the queue
- getServer () : Gets the Message Server the queue reside upon.
- setServer () : Sets the server for this queue instance.
- getMinSequence () : Get the current minimum message sequence number.
- getMaxSequence () : Get the current maximum message sequence number.
- getLastEnqueue () : Gets the Enqueue time of the last message written to the queue.
- getMsgCount () : Get the number of available messages to be read.
- getReceiverCount () Returns the number of connected receivers.
- isSuspended () : Returns a boolean flag indicating if the queue is suspended.
- refreshStatistics () : Refreshes the statistical information.
Topic.java
- getQName () : Returns the name of the topic
- getServer () : Gets the Message Server the topic resides upon.
- setServer () : Sets the server for this topic instance.
- getMinSequence () : Get the current minimum message sequence number.
- getMaxSequence () : Get the current maximum message sequence number.
- getLastEnqueue () : Gets the Enqueue time of the last message written to the queue.
- getMsgCount () : Get the number of available messages to be read.
- getReceiverCount () Returns the number of connected receivers.
- isSuspended () : Returns a boolean flag indicating if the topic is suspended.
- refreshStatistics () : Refreshes the statistical information.
Msg.java
- setMessageProps () : Sets the messages properties as obtain from the server.
- getSequenceNumber () : Gets the message Sequence Number
- getMessageId () : Returns the Message Id
- getStatus () : Returns the status of the message.
- getMessageSize () : Returns the size in byte of the message.
- getDeliveryMode () : Returns the Delivery Mode of the Message
- getPriority () : Returns the Priority of the message.
- getEnqueueTime () : Returns the Date / Time that the message was written to the Queue / Topic
- getType
() : Get the message type.
Creating
the NetBeans Interface
Now that we have created the access class required to retrieve the
Message Server information we need a framework within which this
information will be displayed. To achieve this we will add an addition
node to the Services Tab,
similar to the Servers node, that will contain a list of all JMS
Servers we want to connect to. The information for each of these
Messages servers will be store within a properties file below the
<UserDir>/config/JMSServers directory. BBy default the Server
Nodes will not connect to their specified JMS Message Server but
instead we will provide Connect / Disconnect Actions and a default
(Preferred Action) Double-Click that will connect to the Server. Once
connected tot he Server two specific Node types will be added to the
Server. One of these will represent a Queue whilst the other represents
a Topic. Again on these we will add a number of Actions and a Default
(PreferredAction) that opens a display component to list all the
messages on the Queue/Topic.In this section we will examine the core java classes required to implement the NetBeans Module functionality and describe the key methods:
- AllMsgServersNode.java
- AllMsgServersChildren.java
- AllMsgServersNotifier.java
- NewServerPanel.java
- OneMsgServerNode.java
- OneMsgServerChildren.java
- OneMsgServerNotifier.java
- OneQueueNode.java
- OneTopicNode.java
- MsgListTopComponent.java
- MsgListTopComponentSettings.xml
- MsgListTopComponentWstcref.xml
- RefreshAllMsgServersAction.java
- RefreshMsgServerAction.java
AllMsgServersNode.java
This Java Class extends the AbstractNode specifying what children will exist below the main node and uses the AllMsgServersChildren class to keep track of the list of child nodes. The Node takes care of things such as the context menu and associated actions.
- Methods
- getActions : Get the
following list of Actions that will be displayed in the context Menu
for the top level server node.
- RefreshAllMsgServersAction : Action defined in the
RefreshAllMsgServersAction.java file to simple refresh the list of
child nodes.
- OpenLocalExplorerAction : Permits the user to make a new
Explorer window showing on the JMS Message Servers.
- NewAction : Enables the creation of a new sub-node by
initiating a call to getNewTypes. This is a System Action controlled by
NetBeans.
- getNewTypes : Returns a
list of NewType objects when the NewAction Context menu is selected.
The action provides the actual GUI that will be displayed to collect
the required information. The GUI used to obtain the JMS Server
information is a Disalog generated (using the DialogDisplayer
and DialogDescriptor)
from the NewServerPanel.java. Hence when the NewAction is
selected the Server data will be collected and a single NewType will be
returned with the following create()
method which will show the dialog to collect the Server information and
then if the user selects "Save" create a new msgserver.properties file
in the <userdir>/config/JMSServers directory.
@Override
public void create() throws IOException {
String title = bundle.getString("LBL_NewMsgServerDialogTitle");
String msg = bundle.getString("MSG_NewMsgServerDialogMsg");
NewServerPanel nsp = new NewServerPanel();
Dialog d = DialogDisplayer.getDefault().createDialog(new DialogDescriptor(nsp,title,true,nsp.getButtonActionListener()));
d.pack();
d.setVisible(true);
d = null;
}
AllMsgServersChildren.java
This class is responsible for keeping track of the list Message Servers that exists below the Root node. When first asked for the list it will read all msgserver*.properties files that exist below the <userdir>/config/JMSServer directory (previous created using Add Message Server) and asks the node implementation to keep track of the loaded properties files. This class extends the Children.keys class and therefore we do not need to explicitly keep track of the nodes. Instead we track the keys which represent the nodes. We define, within the implementation, how to create a node for each key.
- Methods
- createNodes : Called by the
implementation whenever needs to construct a child node. It is passed
the Server Properties as the key for which it will make a node and will
return only a single node of type OneMsgServerNode.
- refreshList : When
called this method will read all the msgserver*.properties files and
load them into an ArrayList. Once complete the setKeys method will be
called with the list enabling the sub-node to be displayed, one per
Server, in an unsorted fashion.
private void refreshList() {
List keys = new ArrayList();
Properties msgServerProp = new Properties();
FileObject msgServerPropFile = null;
FileObject jmsServerFolder = Repository.getDefault().getDefaultFileSystem().getRoot().getFileObject(bundle.getString("CONFIG_DirectoryName"));
InputStream is = null;
if (jmsServerFolder != null) {
Enumeration e = jmsServerFolder.getData(false);
while (e.hasMoreElements()) {
msgServerPropFile = (FileObject) e.nextElement();
System.out.println("*** APH-I1 : Message Server Properties Filename : " + msgServerPropFile.getNameExt());
msgServerProp = new Properties();
try {
keys.add(JMSServerPropertyFileManager.loadProperties(msgServerPropFile));
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
// Collections.sort(keys);
setKeys(keys);
}
OneMsgServerNode.java
This Java Class extends the AbstractNode specifying what children will exist below the AllMsgServersNode node and uses the OneMsgServerChildren class to keep track of the child nodes. The Node takes care of things such as the context menu and associated actions.
- Methods
- getActions : Get the
following list of Actions that will be displayed in the context Menu
for the top level server node.
- ConnectAction : Executes the server.connect method for the
associated Msg Server and then if connected changes the icon.
- DisconnectAction : Executes the server.disconnect method for
the associated Message Server and then changes the icon.
- RefreshMsgServerAction : Action defined in the
RefreshMsgServerAction.java file to simple refresh the list of
child nodes.
- OpenLocalExplorerAction : Permits the user to make a new
Explorer window showing on the JMS Message Servers.
- PropertiesAction : Enables the building and display of a properties sheet and is controlled by the execution of createSheet(). This is a System Action controlled by NetBeans.
- getPreferredAction :
This method provides the preferred Action to be executed when the user
Double-Clicks on the node. In the case of the OneMsgServerNode this
will be to connect to the underlying Message Server.
- createSheet :
Configures
the look of the property sheet. This creates a list of properties that
will be displayed within the property sheet. The createSheet method is
not called until there is a need to display the list of properties. For
each property stored against the Message Server we will create a new
Inner class that is a custom property that extends either
PropertySupport.ReadWrite or PropertySupport.ReadOnly each will provide
a getValue and setValue that will access the underlying Message Server
properties.
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set props = sheet.get(Sheet.PROPERTIES);
if (props == null) {
props = Sheet.createPropertiesSet();
sheet.put(props);
}
class NameProp extends PropertySupport.ReadWrite {
public NameProp() {
super("serverName", String.class,
bundle.getString("PROP_JMSServerName"), bundle.getString("HINT_JMSServerName"));
}
public Object getValue() {
return serverName;
}
public void setValue(Object val) {
serverName = val.toString();
OneMsgServerNotifier.changed();
}
}
class ServerProp extends PropertySupport.ReadOnly {
public ServerProp() {
super("server", String.class,
bundle.getString("PROP_JMSServer"), bundle.getString("HINT_JMSServer"));
}
public Object getValue() {
return serverType;
}
public void setValue(Object val) {
serverType = val.toString();
OneMsgServerNotifier.changed();
}
}
class HostProp extends PropertySupport.ReadWrite {
public HostProp() {
super("host", String.class,
bundle.getString("PROP_JMSHost"), bundle.getString("HINT_JMSHost"));
}
public Object getValue() {
return serverHost;
}
public void setValue(Object val) {
serverHost = val.toString();
OneMsgServerNotifier.changed();
}
}
class PortProp extends PropertySupport.ReadWrite {
public PortProp() {
super("port", int.class,
bundle.getString("PROP_JMSPort"), bundle.getString("HINT_JMSPort"));
}
public Object getValue() {
return Integer.parseInt(serverPort);
}
public void setValue(Object val) {
serverPort = val.toString();
OneMsgServerNotifier.changed();
}
}
class UsernameProp extends PropertySupport.ReadWrite {
public UsernameProp() {
super("username", String.class,
bundle.getString("PROP_JMSUsername"), bundle.getString("HINT_JMSUsername"));
}
public Object getValue() {
return serverUsername;
}
public void setValue(Object val) {
serverUsername = val.toString();
OneMsgServerNotifier.changed();
}
}
class PasswordProp extends PropertySupport.ReadWrite {
public PasswordProp() {
super("password", String.class,
bundle.getString("PROP_JMSPassword"), bundle.getString("HINT_JMSPassword"));
}
public Object getValue() {
return serverPassword;
}
public void setValue(Object val) {
serverPassword = val.toString();
OneMsgServerNotifier.changed();
}
}
props.put(new NameProp());
props.put(new ServerProp());
props.put(new HostProp());
props.put(new PortProp());
props.put(new UsernameProp());
props.put(new PasswordProp());
OneMsgServerNotifier.addChangeListener(listener = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
System.out.println("State Change " + ev.getSource());
System.out.println("Port " + msgServerProp.getProperty(bundle.getString("KEY_MsgServerPort")));
System.out.println("Children Node Count :" + children.getNodesCount());
System.out.println("Properties : " + msgServerProp);
saveChanges();
}
});
return sheet;
}
This class is responsible for keeping track of all the Queues and Topics that exist within the selected Message Server. When first asked for the list it will call the getQueues() and getTopics() methods for the associated MsgServer class and ask the node implementation to keep track of them. The class extends the Children.keys class and therefore does not need to explicitly keep track of the node. On returning from this call the keys associated with the node are of two types QueueInterface and TopicInterface and therefore when creating the nodes we will need to take this into account.
- Methods
- createNodes : Called by the
implementation whenever needs to construct a child node. It is passed
either a QueueInterface or TopicInterface as the key for which it will
make a node and will
return only a single node of OneQueueNode or OneTopicNode.
@Override
protected Node[] createNodes(Object key) {
Node[] nodes = new Node[0];
if (key instanceof QueueInterface) nodes = new Node[]{new OneQueueNode((QueueInterface) key)};
else if (key instanceof TopicInterface) nodes = new Node[]{new OneTopicNode((TopicInterface) key)};
return nodes;
}
- refreshList : When
called this method will read all the queues and topics from the message
server and
load them into an ArrayList. Once complete the setKeys method will be
called with the list enabling the sub-node to be displayed, one per
Queue / Topic, in an unsorted fashion.
private void refreshList() {
List keys = new ArrayList();
if (server != null) {
keys = server.getQueues();
keys.addAll(server.getTopics());
}
setKeys(keys);
}
OneQueueNode.java / OneTopicNode.java
Essentially these classes are the same except one will deal with a specific Queue whilst the other deals with a specific Topic. These Java Classes provide the AbstractNode implementation for a single Queue or Topic and the constructor takes a QueueInterface or TopicInterface as the parameters. Because these nodes will never contain any sub-node the constructors call super(Children.LEAF) to indicate to the NetBeans framework that this is the case.
- Methods
- getActions : Get the
following list of Actions that will be displayed in the context Menu
for the top level server node.
- ViewAction : Displays a TopComponent that contains a list of
all messages currently available on the the selected Queue / Topic
- PropertiesAction : Enables the building and display of a properties sheet and is controlled by the execution of createSheet(). This is a System Action controlled by NetBeans.
- getPreferredAction :
This method provides the preferred Action to be executed when the user
Double-Clicks on the node and will execute the ViewAction.
- createSheet :
Configures
the look of the property sheet. This creates a list of properties that
will be displayed within the property sheet. The createSheet method is
not called until there is a need to display the list of properties. For
each available property within the Queue / Topic it will create a new
class of type PropertySupport.ReadOnly.
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set props = sheet.get(Sheet.PROPERTIES);
if (props == null) {
props = Sheet.createPropertiesSet();
sheet.put(props);
}
queue.refreshStatistics();
props.put(new PropertySupport.Name(this));
class SuspendedProp extends PropertySupport.ReadOnly {
public SuspendedProp() {
super("suspended", boolean.class,
bundle.getString("PROP_JMSSuspended"), bundle.getString("HINT_JMSSuspended"));
}
public Object getValue() {
return queue.isSuspended();
}
public void setValue(Object nue) {
// System.setProperty(key, (String) nue);
OneMsgServerNotifier.changed();
}
}
class MinSeqProp extends PropertySupport.ReadOnly {
public MinSeqProp() {
super("minSeq", long.class,
bundle.getString("PROP_JMSMinSeq"), bundle.getString("HINT_JMSMinSeq"));
}
public Object getValue() {
return queue.getMinSequence();
}
public void setValue(Object nue) {
// System.setProperty(key, (String) nue);
OneMsgServerNotifier.changed();
}
}
class MaxSeqProp extends PropertySupport.ReadOnly {
public MaxSeqProp() {
super("maxSeq", long.class,
bundle.getString("PROP_JMSMaxSeq"), bundle.getString("HINT_JMSMaxSeq"));
}
public Object getValue() {
return queue.getMaxSequence();
}
public void setValue(Object nue) {
// System.setProperty(key, (String) nue);
OneMsgServerNotifier.changed();
}
}
class AvailableProp extends PropertySupport.ReadOnly {
public AvailableProp() {
super("available", long.class,
bundle.getString("PROP_JMSAvailable"), bundle.getString("HINT_JMSAvailable"));
}
public Object getValue() {
return queue.getMsgCount();
}
public void setValue(Object nue) {
// System.setProperty(key, (String) nue);
OneMsgServerNotifier.changed();
}
}
class ReceiversProp extends PropertySupport.ReadOnly {
public ReceiversProp() {
super("receivers", long.class,
bundle.getString("PROP_JMSReceivers"), bundle.getString("HINT_JMSReceivers"));
}
public Object getValue() {
return queue.getReceiverCount();
}
public void setValue(Object nue) {
// System.setProperty(key, (String) nue);
OneMsgServerNotifier.changed();
}
}
class LastEnqueueProp extends PropertySupport.ReadOnly {
public LastEnqueueProp() {
super("lastEnqueue", Date.class,
bundle.getString("PROP_JMSLastEnqueue"), bundle.getString("HINT_JMSLastEnqueue"));
}
public Object getValue() {
return queue.getLastEnqueue();
}
public void setValue(Object nue) {
// System.setProperty(key, (String) nue);
OneMsgServerNotifier.changed();
}
}
props.put(new SuspendedProp());
props.put(new MinSeqProp());
props.put(new MaxSeqProp());
props.put(new AvailableProp());
props.put(new ReceiversProp());
props.put(new LastEnqueueProp());
OneMsgServerNotifier.addChangeListener(listener = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
System.out.println("Event :" + ev.toString());
firePropertyChange("value", null, null);
}
});
return sheet;
}
This class is used to display the Messages that reside on either a Queue or a Topic. To created this class, and its associated files, we will create a New Window Component within the project. When this is done NetBeans will generate the skeleton classes required and and example action that can be used to initiate the display of the component. Because we will be calling this from both the OneQueueNode and the OneTopicNode we will not be using the generated Action but rather taking the code and implementing the Inner class ViewMsgAction.
- Right-Click com.sun.aph.nbm.jmsbrowser package and Select New -> Window Component
- Set Window Position as editor and uncheck the "Open on
Application Start" (Next)

- Set the Class Name Prefic to MsgList (Finish)

This will create a number of files and we will now modify the MsgListTopComponent.java to display the data correctly. I will not go into details on how to build the swing component because reviewing the code within NetBeans will show you the required code. In stead I will list the methods that were modified from those created by the New Windows Component call.
- Create two Constructors as follows and remove the existing
constructor.
private MsgListTopComponent(QueueInterface queue) {
this.queue = queue;
initComponents();
// setQName(NbBundle.getMessage(MsgListTopComponent.class, "CTL_MsgListTopComponent"));
setName(queue.getQName());
setDisplayName(queue.getQName());
setToolTipText(NbBundle.getMessage(MsgListTopComponent.class, "HINT_MsgListTopComponent"));
// setIcon(Utilities.loadImage(ICON_PATH, true));
postInitComponents();
}
private MsgListTopComponent(TopicInterface topic) {
this.topic = topic;
initComponents();
// setQName(NbBundle.getMessage(MsgListTopComponent.class, "CTL_MsgListTopComponent"));
setName(topic.getTName());
setDisplayName(topic.getTName());
setToolTipText(NbBundle.getMessage(MsgListTopComponent.class, "HINT_MsgListTopComponent"));
// setIcon(Utilities.loadImage(ICON_PATH, true));
postInitComponents();
}
- Replace the default getDefault()
method with the following two implementations. These methods create the
default Component that will be displayed within the edit area if one
does not exist.
public static synchronized MsgListTopComponent getDefault(QueueInterface queue) {
// if (instance == null)
MsgListTopComponent instance = new MsgListTopComponent(queue);
System.out.println("Getting Default for " + queue);
return instance;
}
public static synchronized MsgListTopComponent getDefault(TopicInterface topic) {
// if (instance == null)
MsgListTopComponent instance = new MsgListTopComponent(topic);
System.out.println("Getting Default for " + topic);
return instance;
}
- Replace the default findInstance()
method with the following two implementations. This static method is
called from the ViewMsgAction Inner class defined within the
OneQueueNode and the OneTopicNode and is used to locate any existing
occurrence of the component. The net result is that for any given Queue
/ Topic name a single tab will be displayed within the Editor area.
This is possible because we set the Name component of this Wiget to be
the name of the Queue / Topic and this is a Unique Id that NetBeans
will track and control. If the Queue / Topic has not be open previously
then an instance will be created and returned from the call.
public static synchronized MsgListTopComponent findInstance(QueueInterface queue) {
TopComponent win = WindowManager.getDefault().findTopComponent(queue.getQName());
if (win == null) {
Logger.getLogger(MsgListTopComponent.class.getName()).warning(
"Cannot find " + queue.getQName() + " component. It will not be located properly in the window system.");
return getDefault(queue);
}
if (win instanceof MsgListTopComponent) {
return (MsgListTopComponent) win;
}
Logger.getLogger(MsgListTopComponent.class.getName()).warning(
"There seem to be multiple components with the '" + queue.getQName() +
"' ID. That is a potential source of errors and unexpected behavior.");
return getDefault(queue);
}
public static synchronized MsgListTopComponent findInstance(TopicInterface topic) {
TopComponent win = WindowManager.getDefault().findTopComponent(topic.getTName());
if (win == null) {
Logger.getLogger(MsgListTopComponent.class.getName()).warning(
"Cannot find " + topic.getTName() + " component. It will not be located properly in the window system.");
return getDefault(topic);
}
if (win instanceof MsgListTopComponent) {
return (MsgListTopComponent) win;
}
Logger.getLogger(MsgListTopComponent.class.getName()).warning(
"There seem to be multiple components with the '" + topic.getTName() +
"' ID. That is a potential source of errors and unexpected behavior.");
return getDefault(topic);
}
- Overide the getPreferedId() method with the following. This will
return the preferred Id that the findInstance will be looking for.
@Override
protected String preferredID() {
return getName();
}
- Create the refreshData() method, as follows, and add into the
postInitComponent() which you will need to create. Also link it into
the Action associated with the refresh button.
// Methods
private void postInitComponents() {
refreshData();
}
private void refreshData() {
List<MsgInterface> msgList = new ArrayList<MsgInterface>();
cbSuspended.setSelected(false);
tfMinSeq.setText("");
tfMaxSeq.setText("");
tfAvailable.setText("");
tfReceivers.setText("");
tfLastEnqueue.setText("");
System.out.println("Queue : " + queue);
System.out.println("Topic : " + topic);
for (int i = ((DefaultTableModel) tblMessages.getModel()).getRowCount(); i > 0; i--) {
((DefaultTableModel) tblMessages.getModel()).removeRow(0);
}
if (queue != null) {
cbSuspended.setSelected(queue.isSuspended());
tfMinSeq.setText(Long.toString(queue.getMinSequence()));
tfMaxSeq.setText(Long.toString(queue.getMaxSequence()));
tfAvailable.setText(Long.toString(queue.getMsgCount()));
tfReceivers.setText(Long.toString(queue.getReceiverCount()));
tfLastEnqueue.setText(queue.getLastEnqueue().toString());
msgList = queue.getMessages();
} else if (topic != null) {
cbSuspended.setSelected(topic.isSuspended());
tfMinSeq.setText(Long.toString(topic.getMinSequence()));
tfMaxSeq.setText(Long.toString(topic.getMaxSequence()));
tfAvailable.setText(Long.toString(topic.getMsgCount()));
tfReceivers.setText(Long.toString(topic.getReceiverCount()));
tfLastEnqueue.setText(topic.getLastEnqueue().toString());
msgList = topic.getMessages();
}
String[][] tableData = new String[msgList.size()][MessagesTableModel.COLUMNS];
Iterator<MsgInterface> msgItr = msgList.iterator();
int rowCnt = 0;
MsgInterface msg = null;
int i = 0;
while (msgItr.hasNext()) {
msg = msgItr.next();
i=0;
tableData[rowCnt][i++] = msg.getSequenceNumber();
tableData[rowCnt][i++] = msg.getMessageId();
tableData[rowCnt][i++] = msg.getStatus();
tableData[rowCnt][i++] = msg.getMessageSize();
tableData[rowCnt][i++] = msg.getEnqueueTime();
tableData[rowCnt][i++] = msg.getPriority();
tableData[rowCnt][i++] = msg.getDeliveryMode();
tableData[rowCnt][i++] = msg.getType();
rowCnt++;
}
for (i = 0; i < tableData.length; i++) {
Object[] row = tableData[i];
((DefaultTableModel) tblMessages.getModel()).addRow(row);
}
}
Within the OneQueueNode.java and the OneTopicNode.java the following Inner class will need to be created. This will define the ViewMsgAction that appears in the context menu.
private class ViewMsgAction extends AbstractAction {
public ViewMsgAction() {
super(bundle.getString("ACTION_ViewMessages"));
}
public void actionPerformed(ActionEvent evt) {
TopComponent win = MsgListTopComponent.findInstance(queue);
win.setDisplayName(queue.getQName());
win.open();
win.requestActive();
}
}
AllMsgServersNotifier.java / OneMsgSeverNotifier.java
These Java classes manage routing events whenever their are changes to the appropriate nodes. The child node will register with the appropriate Notifier.
RefreshAllMsgServersAction.java / RefreshMsgServerAction.java
These Java classes provide Refresh actions to the AllMsgServersNode and OneMsgServerNode and appear as the "Refresh" option in the appropriate context menu. They force a refresh to occur updating the display of the information and refreshes the list of sub-nodes.
Creating
the Supporting Files
Once we have successfully coded the main files we must specify how we
would like our Module to impact the filesystem and what labels and text
we want to display the the user. The layer.xml file and the
Bundle.properties file are used for this.- Add the following entry to the layer.xml file :
<folder name="UI">
<folder name="Runtime">
<file name="com.sun.aph.nbm.jmsbrowser.AllMsgServersNode.instance"/>
</folder>
</folder>
- Add the following to the Bundle.properties file:
CTL_MsgListAction=MsgList
CTL_MsgListTopComponent=MsgList Window
HINT_MsgListTopComponent=This is a MsgList window
CONFIG_DirectoryName=JMSServers
LBL_NewMsgServer=New Message Server
LBL_NewMsgServerDialogTitle=New Message Server
MSG_NewMsgServerDialogMsg=New Message Server Name
KEY_MsgServerName=MsgServerName
KEY_MsgServerHost=MsgServerHost
KEY_MsgServerPort=MsgServerPort
KEY_MsgServerUsername=MsgServerUsername
KEY_MsgServerPassword=MsgServerPassword
KEY_MsgServerType=MsgServerType
KEY_MsgServerConfigFile=MsgServerConfigFile
LBL_AllMsgServersNode=JMS Servers
HINT_AllMsgServersNode=JMS Message Server
ICON_AllMsgServersNode=com/sun/aph/nbm/jmsbrowser/icon/messageserver.png
LBL_OneMsgServerNode=JMS Message Server
HINT_OneMsgServerNode=Sun SeeBeyond JMS Message Server
ICON_OneMsgServerNode=com/sun/aph/nbm/jmsbrowser/icon/messageserver.png
ICON_OneMsgServerNodeDisconnected=com/sun/aph/nbm/jmsbrowser/icon/application_server.png
ICON_OneMsgServerNodeConnected=com/sun/aph/nbm/jmsbrowser/icon/application_server_run.png
LBL_RefreshMsgServer=Refresh
LBL_RefreshAllMsgServers=Refresh
ICON_OneQueueNode=com/sun/aph/nbm/jmsbrowser/icon/queue.png
HINT_OneQueueNode=JMS Queue
ICON_OneTopicNode=com/sun/aph/nbm/jmsbrowser/icon/topic.png
HINT_OneTopicNode=JMS Topic
PROP_JMSServerName=Name
HINT_JMSServerName=Name of the Server Connection.
PROP_JMSServer=Server
HINT_JMSServer=JMS Message Server.
PROP_JMSHost=Host
HINT_JMSHost=JMS Message Server host name or IP Address.
PROP_JMSPort=Port
HINT_JMSPort=JMS Message Server port number.
PROP_JMSUsername=Username
HINT_JMSUsername=JMS Message Server Username.
PROP_JMSPassword=Password
HINT_JMSPassword=JMS Message Server Password.
PROP_JMSSuspended=Suspended
HINT_JMSSuspended=Flag to indicate if the queue/topic is suspended.
PROP_JMSMinSeq=Minimum Sequence
HINT_JMSMinSeq=Minimum Message Sequence Number.
PROP_JMSMaxSeq=Maximum Sequence
HINT_JMSMaxSeq=Maximum Message Sequence Number.
PROP_JMSAvailable=Available Count
HINT_JMSAvailable=Number of message available to be read.
PROP_JMSReceivers=Receiver Count
HINT_JMSReceivers=Number of Receivers.
PROP_JMSLastEnqueue=Last Publish Date
HINT_JMSLastEnqueue=Number of Receivers.
ACTION_ViewMessages=View Messages
ACTION_ServerConnect=Connect
ACTION_ServerDisconnect=Disconnect
- In addition we will add a number of icons, 16 x 16, that will be
displayed on the nodes. As long as the ICON_* entries within the
Bundle.properties files match the names (relative) of the icon files
these will be displayed. The attached project contains the appropriate
icon images used within this blog.
Compiling, Installing and Running your Module
Now that we have completed the module it is time to try it out. NetBeans provides the ability to test out a module without having to install it with the Development environment so we will use this to run the module and then when happy generate the NBM to be installed in the Development environment.
- In the Projects window Right-Click on the JMSBroswerSuite project and choose "Clean and Build" this will remove all compiled files and the test user directory created in the next step.
- In the Projects window Right-Click on the JMSBrowser project and
select "Install/Reload in Target Platform".
The module is built and installed in the target IDE / Platform. The target IDE/Platform opens so that we can try out our new Module. The default target IDE/Platform is the installation used by your current instance of the development IDE. When we run the module a temporay test user directory will be created below th JMSBrowserSuite build directory. - In the IDE's Services Window (Ctrl-5) you will see a new "JMS Servers" Node. Selecting this will show that it is currently empty.
- Right-Click on the JMS Servers node and select "Add New Message
Server". Fill in the resulting Dialog with the details of a Java CAPS 6
Message Server.

Select "Save" and the server details will be added (created as a file in <userdir>/config/JMSServers) to the JMS Server node. If the node is not refreshed and displayed then Rick-Click and select Refresh.

- Right-Click (or double-click) on the newly created Message Server
node and select Connect. This will connect tot he Java CAPS 6 Message
server and once connected the icon will change. You can now expand the
node and it will display all the Queues and Topics available on the
Server.

- Right-Clicking one of the Queues / Topics and selecting
Properties will display the summary information for the Queue / Topic.

- If we now double-click on a specific Queue / Topic the messages
associated with it will be displayed within a new tab in the edit area
of NetBeans.

- Finally if we Right-Click on the Newly created Server Node we can
review and change the Properties associated with the Server and these
will be changed within the backing file.

- Once we are happy with the functionality of the Module we can
close down the test IDE and build the appropriate NBM files for
distribution. This is done by Rick-Clicking the JMSBrowserSuite and
select "Create NBMs" which will generate the appropriate NBMs that can
then be installed into your development IDE.
- Add Queues
- Delete Queues
- View Messages
- Send Messages
- Remove Messages
- Add Subscribers / Read Messages
- Auto Refresh
- Sun MQ Message Server Functionality.
Resources
Keywords
- Java CAPS 6
- Java Message Server JMS
- Monitoring
- Management
- NetBeans Plug-in Tutorial
- Nodes API
- File System API
- Dialog API








hi dante,
this is something i was missing for a long time now and posted here
http://forums.sun.com/thread.jspa?threadID=5311464
had logged an enhancement request at openmq via openmq issue tracker.
i love to see someone from sun picking this up a little bit.
regards chris
Posted by Christian Brennsteiner on September 09, 2008 at 10:08 PM GMT #
THANK YOU!
Posted by sysprv on September 10, 2008 at 06:08 AM GMT #