User: andreas
Date: 00/11/25 14:23:31
Modified: examples/jboss.admin/src/org/jboss/jBossAdmin
RemoteResource.java
Added: examples/jboss.admin/src/org/jboss/jBossAdmin
GenericMBeanCustomizer.java
Log:
Created a new GenericMBeanCustomizer to display the
remote MBean overview dynamic based on the MBean
description.
It is still buggy but evolving.
Revision Changes Path
1.4 +7 -5
ejx/examples/jboss.admin/src/org/jboss/jBossAdmin/RemoteResource.java
Index: RemoteResource.java
===================================================================
RCS file:
/products/cvs/ejboss/ejx/examples/jboss.admin/src/org/jboss/jBossAdmin/RemoteResource.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- RemoteResource.java 2000/11/24 07:51:43 1.3
+++ RemoteResource.java 2000/11/25 22:23:31 1.4
@@ -37,7 +37,7 @@
* <description>
*
* @author <A href="mailto:[EMAIL PROTECTED]">Andreas "Mad" Schaefer</A>
-* @version $Revision: 1.3 $
+* @version $Revision: 1.4 $
**/
public class RemoteResource
extends BeanContextSupport
@@ -183,19 +183,21 @@
// BeanContextContainerProxy implementation -----------------
public Component getComponent() {
-/*
+// /*
if( c == null ) {
- c = new GenericCustomizer();
- c.setObject( this );
+ c = new GenericMBeanCustomizer();
+ c.setObject( new GenericMBeanCustomizer.Resource( mConnector, mName ) );
}
return (Component) c;
-*/
+// */
+/*
if( mViewer == null ) {
mViewer = new JScrollPane(
new Viewer()
);
}
return mViewer;
+*/
}
// Package protected ---------------------------------------------
1.1
ejx/examples/jboss.admin/src/org/jboss/jBossAdmin/GenericMBeanCustomizer.java
Index: GenericMBeanCustomizer.java
===================================================================
/*
* jBoss, the OpenSource EJB server
*
* Distributable under GPL license.
* See terms of license at gnu.org.
*/
package org.jboss.jBossAdmin;
import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.Customizer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.beans.PropertyVetoException;
import java.beans.beancontext.BeanContext;
import java.beans.beancontext.BeanContextChild;
import java.beans.beancontext.BeanContextProxy;
import java.beans.beancontext.BeanContextServiceProvider;
import java.beans.beancontext.BeanContextServices;
import java.beans.beancontext.BeanContextServicesSupport;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import javax.management.Attribute;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanFeatureInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectName;
import javax.swing.*;
import com.dreambean.awt.GenericMethodDialog;
import com.dreambean.awt.GenericPropertyCustomizer;
import org.jboss.jmx.interfaces.JMXConnector;
/**
* Generic JavaBean customizer. It creates property editors for all properties and
buttons for all methods.
* Create a BeanInfo class for the JavaBean that you want to be able to customize
for maximum control over the
* appearance of the customizer.
* The GenericCustomizer has one extension to the standard JavaBeans behavior: if a
propertyeditor implements BeanContextProxy
* the GenericCustomizer will add it to a beancontext method so that the
propertyeditor can use that contextual info to customize itself.
* For example, the legal values of a property might depend on which object is
being edited.
* The object being edited is made available as a BeanContext service /w the class
of the object. This allows the propertyeditors to extract
* dynamic info for customization.
*
* @author Rickard �berg ([EMAIL PROTECTED])
* @created November 24, 2000
* @version $Revision: 1.1 $
*/
public class GenericMBeanCustomizer
extends JScrollPane
implements Customizer, BeanContextProxy
{
// Attributes ----------------------------------------------------
/**
* Description of the Field
*/
private Resource mResource;
/**
* Description of the Field
*/
private JPanel mPanel;
/**
* Description of the Field
*/
private JPanel mGUI;
/**
* Description of the Field
*/
private JComponent mPreviousBean = null;
/**
* Description of the Field
*/
private BeanContextServices bcProxy = null;
// Constructor ---------------------------------------------------
/**
* Create a new customizer
*/
public GenericMBeanCustomizer() {
super( new JPanel() );
mPanel = ( JPanel ) getViewport().getView();
mPanel.setLayout( new GridBagLayout() );
}
/**
* Convenience method to create a customizer and set the object to be
customized
*
* @param obj the customized object
*/
public GenericMBeanCustomizer( Resource pResource ) {
this();
setObject( pResource );
}
// Customizer implementation -------------------------------------
/**
* Set the object to be customized. Inspects the object and creates editors
and buttons
*
* @param object
*/
public void setObject( Object pObject ) {
try {
mPanel.removeAll();
if( !( pObject instanceof Resource ) ) {
validate();
repaint();
return;
}
mResource = (Resource) pObject;
ObjectName lName = mResource.getName();
MBeanInfo lInfo = mResource.getConnector().getMBeanInfo( lName
);
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets( 5, 5, 5, 5 );
c.anchor = GridBagConstraints.NORTH;
c.weighty = 1;
/* AS No BeanInfo used here -> remove later
BeanInfo info;
if( object instanceof BeanInfo ) {
info = ( BeanInfo ) object;
}
else {
info = Introspector.getBeanInfo( object.getClass() );
}
*/
mGUI = new JPanel( new GridBagLayout() );
mGUI.setBorder( BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), mResource.getName().toString() ) );
addInfo( "Domain", lName.getDomain() );
addInfo( "Description", lInfo.getDescription() );
addSubtitle( "Attributes" );
Iterator i = Arrays.asList( lInfo.getAttributes() ).iterator();
while( i.hasNext() ) {
MBeanAttributeInfo lFeature = (MBeanAttributeInfo)
i.next();
String lType = lFeature.getType();
Class lClass = null;
if( lType.equals( "int" ) ) {
lClass = Integer.TYPE;
}
else if( lType.equals( "short" ) ) {
lClass = Short.TYPE;
}
else if( lType.equals( "long" ) ) {
lClass = Long.TYPE;
}
else if( lType.equals( "byte" ) ) {
lClass = Byte.TYPE;
}
else if( lType.equals( "char" ) ) {
lClass = Character.TYPE;
}
else if( lType.equals( "float" ) ) {
lClass = Float.TYPE;
}
else if( lType.equals( "double" ) ) {
lClass = Double.TYPE;
}
else if( lType.equals( "boolean" ) ) {
lClass = Boolean.TYPE;
}
if( lClass == null ) {
lClass = Class.forName( lType );
}
System.out.println( "Got class: " + lClass );
PropertyEditor lEditor =
PropertyEditorManager.findEditor(
lClass
);
// If editor is null then is uses the default string
editor
addProperty( lEditor, lFeature );
}
addSubtitle( "Operations" );
i = Arrays.asList( lInfo.getOperations() ).iterator();
while( i.hasNext() ) {
MBeanOperationInfo lFeature = (MBeanOperationInfo)
i.next();
addMethod( lFeature );
}
addSubtitle( "Notifications" );
i = Arrays.asList( lInfo.getNotifications() ).iterator();
while( i.hasNext() ) {
MBeanNotificationInfo lFeature =
(MBeanNotificationInfo) i.next();
addMethod( lFeature );
}
/* AS No BeanInfo used here -> remove later
// Properties
pd = info.getPropertyDescriptors();
if( pd != null ) {
if( info.getBeanDescriptor().getValue( "propertyorder"
) == null ) {
// Order is not given
for( int i = 0; i < pd.length; i++ ) {
if(
pd[i].getReadMethod().getDeclaringClass().equals( Object.class ) ) {
continue;
}
if( pd[i].isHidden() ) {
continue;
}
PropertyEditor editor = null;
Class cl =
pd[i].getPropertyEditorClass();
if( cl != null ) {
editor = ( PropertyEditor )
cl.newInstance();
}
else {
editor =
PropertyEditorManager.findEditor( pd[i].getPropertyType() );
}
if( editor != null ) {
addProperty( editor, pd[i] );
}
c.weighty = 1;
}
}
else {
// Order of properties has been given
for( StringTokenizer token = new
StringTokenizer( ( String ) info.getBeanDescriptor().getValue( "propertyorder" ), ":"
); token.hasMoreTokens(); ) {
String propName = token.nextToken();
for( int i = 0; i < pd.length; i++ ) {
if( !pd[i].getName().equals(
propName ) ) {
continue;
}
if( pd[i].isHidden() ) {
continue;
}
PropertyEditor editor = null;
Class cl =
pd[i].getPropertyEditorClass();
if( cl != null ) {
editor = (
PropertyEditor ) cl.newInstance();
}
else {
editor =
PropertyEditorManager.findEditor( pd[i].getPropertyType() );
}
if( editor != null ) {
addProperty( editor,
pd[i] );
}
c.weighty = 1;
}
}
}
}
// Methods
if( showMethods ) {
md = info.getMethodDescriptors();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
if( md != null ) {
for( int i = 0; i < md.length; i++ ) {
if( md[i].getName().startsWith( "get"
) ||
md[i].getName().startsWith( "set" ) ||
md[i].getName().startsWith( "is" ) ) {
continue;
}
JButton button = new JButton(
md[i].getDisplayName() );
button.setToolTipText(
md[i].getShortDescription() );
( ( GridBagLayout )
beanGui.getLayout() ).setConstraints( button, c );
beanGui.add( button );
button.addActionListener( new
MethodInvoker( md[i] ) );
}
}
}
*/
c.weighty = 0;
c.weightx = 1;
c.fill = GridBagConstraints.BOTH;
( ( GridBagLayout ) mPanel.getLayout() ).setConstraints( mGUI,
c );
mPanel.add( mGUI );
validate();
repaint();
}
catch( Exception e ) {
System.out.println( "Exception occurred" );
e.printStackTrace();
}
}
// BeanContextProxy ----------------------------------------------
/**
* Gets the BeanContextProxy attribute of the GenericMBeanCustomizer object
*
* @return The BeanContextProxy value
*/
public BeanContextChild getBeanContextProxy() {
if( bcProxy == null ) {
bcProxy = new BeanContextServicesSupport();
bcProxy.addService( mResource.getClass(),
new BeanContextServiceProvider() {
/**
* Gets the CurrentServiceSelectors attribute
of the GenericMBeanCustomizer object
*
* @param bcs Description of
Parameter
* @param serviceClass Description of
Parameter
* @return The
CurrentServiceSelectors value
*/
public Iterator getCurrentServiceSelectors(
BeanContextServices bcs, Class serviceClass ) {
return null;
}
/**
* Gets the Service attribute of the
GenericMBeanCustomizer object
*
* @param bcs Description of
Parameter
* @param requestor Description of
Parameter
* @param serviceClass Description of
Parameter
* @param serviceSelector Description of
Parameter
* @return The Service value
*/
public Object getService( BeanContextServices
bcs, Object requestor, Class serviceClass, Object serviceSelector ) {
return mResource;
}
/**
* Description of the Method
*
* @param bcs Description of Parameter
* @param requestor Description of Parameter
* @param service Description of Parameter
*/
public void releaseService(
BeanContextServices bcs, Object requestor, Object service ) {
}
} );
// Make object available as service
// TODO
}
return bcProxy;
}
// Public --------------------------------------------------------
public void addInfo( String pDescription, String pValue ) {
}
public void addSubtitle( String pTitle ) {
}
public void addMethod( MBeanFeatureInfo pInfo ) {
}
/**
* Add a property to the customizer
*
* @param editor
* @param pd
*/
public void addProperty( PropertyEditor pEditor, MBeanAttributeInfo pInfo ) {
// If the PropertyEditor is a BeanContextChild: put it into the tree
// This lets the editor find contextual info!
if( pEditor instanceof BeanContextProxy ) {
( ( BeanContext ) getBeanContextProxy() ).add( pEditor );
}
if( pEditor == null ) {
System.out.println( "Editor is null: " + pInfo.getName() + ",
type: " + pInfo.getType() );
return;
}
try {
// Try to set the value to the editor. If not possible do
nothing because
// this should not change the remote Resource
if( pInfo.isReadable() ) {
pEditor.setValue(
mResource.getConnector().getAttribute(
mResource.getName(), pInfo.getName() )
);
}
}
catch( Exception e ) {
e.printStackTrace();
}
JLabel lName = new JLabel( pInfo.getName() + ":", JLabel.RIGHT );
lName.setToolTipText( pInfo.getDescription() );
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets( 5, 5, 5, 5 );
c.anchor = GridBagConstraints.NORTH;
c.weighty = 1;
c.gridwidth = GridBagConstraints.RELATIVE;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0;
( ( GridBagLayout ) mGUI.getLayout() ).setConstraints( lName, c );
mGUI.add( lName );
Component lEditorBean;
if( pEditor.supportsCustomEditor() ) {
lEditorBean = pEditor.getCustomEditor();
if( lEditorBean instanceof JComponent ) {
if( mPreviousBean != null ) {
mPreviousBean.setNextFocusableComponent(
lEditorBean );
}
mPreviousBean = ( JComponent ) lEditorBean;
}
}
else {
String[] lTags = pEditor.getTags();
if( lTags != null ) {
lEditorBean = new GenericPropertyCustomizer( pEditor,
lTags );
if( mPreviousBean != null ) {
mPreviousBean.setNextFocusableComponent(
lEditorBean );
}
mPreviousBean = ( JComponent ) lEditorBean;
}
else {
if( pInfo.isWritable() ) {
lEditorBean = new GenericPropertyCustomizer(
pEditor );
if( mPreviousBean != null ) {
mPreviousBean.setNextFocusableComponent( lEditorBean );
}
mPreviousBean = ( JComponent ) lEditorBean;
}
else {
final JLabel lLabel = new JLabel(
pEditor.getAsText() );
final PropertyEditor lEditor = pEditor;
lEditorBean = lLabel;
pEditor.addPropertyChangeListener(
new PropertyChangeListener() {
/**
* Description of the Method
*
* @param evt Description of
Parameter
*/
public void propertyChange(
PropertyChangeEvent evt ) {
lLabel.setText(
lEditor.getAsText() );
}
} );
}
}
}
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
( ( GridBagLayout ) mGUI.getLayout() ).setConstraints( lEditorBean, c
);
mGUI.add( lEditorBean );
// Read-only?
if( pInfo.isWritable() ) {
pEditor.addPropertyChangeListener( new BeanUpdater( pInfo ) );
}
/* AS Check later
try {
Method addPCL = object.getClass().getMethod(
"addPropertyChangeListener", new Class[]{String.class, PropertyChangeListener.class} );
addPCL.invoke( object, new Object[]{ pInfo.getName(), new
EditorUpdater( pEditor, pInfo.getName() )} );
}
catch( Exception e ) {
try {
Method addPCL = object.getClass().getMethod(
"addPropertyChangeListener", new Class[]{PropertyChangeListener.class} );
addPCL.invoke( object, new Object[]{ new
EditorUpdater( pEditor, pInfo )} );
}
catch( Exception ex ) {
}
}
*/
}
// Protected ---------------------------------------------
/**
* Fire a property change. This is a workaround for firePropertyChange not
being visible to the inner classes(?)
*
* @param name
* @param oldVal
* @param newVal
*/
protected void updated( String name, Object oldVal, Object newVal ) {
firePropertyChange( name, oldVal, newVal );
}
// Protected ---------------------------------------------
/**
* Description of the Method
*
* @param out Description of Parameter
* @exception IOException Description of Exception
*/
private void writeObject( java.io.ObjectOutputStream out )
throws IOException {
System.out.println( "GenericCustomizer writeObject" );
}
// Inner classes -------------------------------------------------
/**
* This class makes sure that the object is updated with the customizer
changes
*
* @author andreass
* @created November 24, 2000
*/
class BeanUpdater
implements PropertyChangeListener {
/**
* Description of the Field
*/
MBeanAttributeInfo mInfo;
/**
* Constructor for the BeanUpdater object
*
* @param pd Description of Parameter
*/
public BeanUpdater( MBeanAttributeInfo pInfo ) {
mInfo = pInfo;
}
/**
* Description of the Method
*
* @param evt Description of Parameter
*/
public void propertyChange( PropertyChangeEvent pEvent ) {
Object lOld = null;
try {
if( mInfo.isReadable() ) {
lOld = mResource.getConnector().getAttribute(
mResource.getName(),
mInfo.getName()
);
}
Object lNew = ( ( PropertyEditor ) pEvent.getSource()
).getValue();
mResource.getConnector().setAttribute(
mResource.getName(),
new Attribute(
mInfo.getName(),
lNew
)
);
updated( mInfo.getName(), lOld, lNew );
}
/* AS Adapt to the JMXConnector exceptions
catch( InvocationTargetException e ) {
if( e.getTargetException() instanceof
PropertyVetoException ) {
JOptionPane.showMessageDialog(
(Frame)
SwingUtilities.windowForComponent( GenericMBeanCustomizer.this ),
"Could not change value:" +
e.getTargetException().getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE
);
}
}
*/
catch( Exception e ) {
System.err.println( e );
}
}
}
/**
* This class makes sure that the customizer is updated with the object
changes
*
* @author andreass
* @created November 24, 2000
*/
class EditorUpdater
implements PropertyChangeListener {
/**
* Description of the Field
*/
PropertyEditor mEditor;
/**
* Description of the Field
*/
String mName;
/**
* Description of the Field
*/
MBeanAttributeInfo mInfo;
/**
* Constructor for the EditorUpdater object
*
* @param e Description of Parameter
* @param pd Description of Parameter
*/
public EditorUpdater( PropertyEditor pEditor, MBeanAttributeInfo pInfo
) {
mEditor = pEditor;
mInfo = pInfo;
}
/**
* Constructor for the EditorUpdater object
*
* @param e Description of Parameter
* @param name Description of Parameter
*/
public EditorUpdater( PropertyEditor pEditor, String pName ) {
mEditor = pEditor;
mName = pName;
}
/**
* Description of the Method
*
* @param evt Description of Parameter
*/
public void propertyChange( PropertyChangeEvent pEvent ) {
if( mName != null && pEvent.getPropertyName() != null ) {
if( !pEvent.getPropertyName().equals( mName ) ) {
return;
}
}
if( pEvent.getPropertyName() != null ) {
if( !mEditor.getValue().equals( pEvent.getNewValue() )
) {
mEditor.setValue( pEvent.getNewValue() );
}
}
else {
try {
Object lValue =
mResource.getConnector().getAttribute(
mResource.getName(),
pEvent.getSource() + ""
);
if( mEditor != null && !mEditor.equals(
mEditor.getValue() ) ) {
mEditor.setValue( lValue );
}
}
catch( Exception e ) {
}
}
}
}
/**
* This class handles method invocations
*
* @author andreass
* @created November 24, 2000
*/
class MethodInvoker
implements ActionListener {
/**
* Description of the Field
*/
MBeanOperationInfo mInfo;
/**
* Constructor for the MethodInvoker object
*
* @param md Description of Parameter
*/
MethodInvoker( MBeanOperationInfo pInfo ) {
mInfo = pInfo;
}
/**
* Description of the Method
*
* @param e Description of Parameter
*/
public void actionPerformed( ActionEvent e ) {
Container lFrame = mPanel;
while( !( lFrame instanceof Frame ) ) {
lFrame = lFrame.getParent();
}
// No parameters->invoke right away
MBeanParameterInfo[] lParameters = mInfo.getSignature();
if( lParameters.length == 0 ) {
try {
mResource.getConnector().invoke(
mResource.getName(),
mInfo.getName(),
new Object[] {},
new String[] {}
);
}
/* AS Deal with the MBean Exceptions and not with reflection one
catch( InvocationTargetException ex ) {
ex.getTargetException().printStackTrace();
JOptionPane.showMessageDialog( lFrame,
ex.getTargetException().getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
}
*/
catch( Exception ex ) {
System.err.println( ex );
JOptionPane.showMessageDialog( lFrame, "An
exception occured. Check log for details", "Error", JOptionPane.ERROR_MESSAGE );
}
}
else {
/* AS Make a new class using MBeanOperationInfo instead of "md"
new GenericMethodDialog( object, md, ( Frame ) lFrame
);
*/
}
}
}
public static class Resource {
private JMXConnector mConnector;
private ObjectName mName;
public Resource( JMXConnector pConnector, ObjectName pName ) {
if( pConnector == null || pName == null ) {
throw new IllegalArgumentException( "Both arguments
must be defined" );
}
mConnector = pConnector;
mName = pName;
}
public JMXConnector getConnector() {
return mConnector;
}
public ObjectName getName() {
return mName;
}
}
}