Java Dynamic Management Kit 5.1 Tutorial

23.2.2 Context Implementation

An agent wanting to implement context checking on a legacy connector first needs to extend the MBeanServerChecker class. This class retrieves the context object and determines whether any given operation is allowed.


Example 23–3 Implementation of the Context Checker

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.QueryExp;

import com.sun.jdmk.MBeanServerChecker;
import com.sun.jdmk.OperationContext;

public class ContextChecker extends MBeanServerChecker {

    // Constructor
    public ContextChecker(MBeanServer mbs) {
        super(mbs);
    }

    // Implementation of the abstract methods of the
    // MBeanServerChecker class: for each of the specific
    // checks, we just print out a trace of being called.
    [...]

    protected void checkWrite( String methodName,
                               ObjectName objectName) {
        System.out.println("checkWrite(\"" + methodName +
                           "\", " + objectName + ")");
    }

    protected void checkQuery( String methodName,
                               ObjectName name,
                               QueryExp query) {
        System.out.println("checkQuery(\"" + methodName +
                           "\", " + name + ", " + query + ")");
    }

    [...]

    /**
     * This is where we implement the check that requires every
     * operation to be called with an OperationContext whose
     * toString() method returns the string "nice".
     */
    protected void checkAny( String methodName,
                             ObjectName objectName ) {

        System.out.println("checkAny(\"" + methodName + "\", " +
                            objectName);
        OperationContext context = getOperationContext();
        System.out.println("  OperationContext: " + context);

        if (context == null || !context.toString().equals("nice")) {
            RuntimeException ex =
                new SecurityException("  Bad context: " + context);
            ex.printStackTrace();
            throw ex;
        }
    }

}

The agent application then instantiates its context checkers and stacks them between the communicator servers and the MBean server. Each communicator server has its own stack, although filters and context checkers can be shared. The agent performs the stacking inside a synchronized block because other threads can try to do stacking simultaneously.


Example 23–4 Stacking MBean Server and Context Checkers

// Create MBeanServer
//
MBeanServer server = MBeanServerFactory.createMBeanServer();

/* Create context checker.  The argument to the constructor is
 * our MBean server to which all requests will be forwarded
 */
ContextChecker contextChecker = new ContextChecker( server );


[...] // Create HTTP connector server

/* Add the context checker to this HTTP connector server.
 * We point it at the context checker which already points
 * to the actual MBean server.
 * It is good policy to check that we are not sidetracking
 * an existing stack of MBean servers before setting ours.
 */
synchronized (http) {
    if (http.getMBeanServer() != server) {
        System.err.println("After registering connector MBean, " +
           "http.getMBeanServer() != " + "our MBeanServer");
        System.exit(1);
    }
    http.setMBeanServer(contextChecker);
}

Finally, the manager operation defines a context object class and then provides a context object instance through its connector client.


Example 23–5 Setting the Context in the Connector Client

/* In this example, the agent checks the OperationContext of
   each operation by examining its toString() method, so we
   define a simple implementation of OperationContext whose
   toString() is a constant string supplied in the constructor
 */
class StringOperationContext
          implements OperationContext, Cloneable {

    private String s;

    StringOperationContext(String s) {
        this.s = s;
    }

    public String toString() {
        return s;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

// the contextName must be provided on the command line
OperationContext context =
    new StringOperationContext(contextName);

[...]

// The context is set for all requests issued through
// the connector client; it can be changed at any time
connector.setOperationContext(context);