Access control for partial exposure

Gain high-speed, fine-grained access control for Java fields and methods

1 2 Page 2
Page 2 of 2
// ********* ExtendedServer ********
public class ExtendedServer extends Server {
   
    private void shakeRattleAndRoll() {
        System.out.println("SHAKE ... RATTLE AN' ROLL!!!");
    }
    private void getUpAndBoogy() {
        System.out.println("GET UP ... AND BOOOOOOOGGGYYYYY!!!");
    }
    private class ShakeRattleAndRoll extends VirtualMethod {
        public void call() {
            shakeRattleAndRoll();
        }
    }
    private class GetUpAndBoogy extends VirtualMethod {
        public void call() {
            getUpAndBoogy();
        }
    }
    public ExtendedClient getClient() {
        return new Client(new ShakeRattleAndRoll(), new ShakeRattleAndRoll());
    }
}
// ********* ExtendedClient ********
public class ExtendedClient extends Client {
    private VirtualMethod shakeRattleAndRoll, getUpAndBoogy;
    ExtendedClient(VirtualMethod shakeRattleAndRoll, VirtualMethod
getUpAndBoogy) {
        this.shakeRattleAndRoll = shakeRattleAndRoll;
        this.getUpAndBoogy = getUpAndBoogy;
    }
    public void demonstrateAccess() {
        shakeRattleAndRoll.call();
        getUpAndBoogy.call();
    }
}

There are many variations of the Access Control pattern. The following version allows only Server to call a method on Client that inserts a VirtualMethod into Client. Calling this method multiple times (to insert multiple VirtualMethods) eliminates the clutter and inconvenience demonstrated above, and makes it easy to increase Client's access to Server's private members.

Access Control pattern improved

Here is the revised version of the Accesss Control pattern:

// ********* VirtualMethodScope ********
package vault;
public abstract class VirtualMethodScope {
    protected abstract class VirtualMethod {
        protected abstract void call();
    }
}

Both Client and Server descend from VirtualMethodScope, and both also live in a different package than VirtualMethodScope. Therefore, within the scope of the working package (the package of Client and Server), only Client, Server, and their descendents can access VirtualMethod, so this version's result is tighter access control. However, the principle argued above still holds, since a Client developer can still expose a public method that calls the private method we've entrusted him with!

// ********* ClientBaseClass ********
package vault;
import java.util.HashMap;
public abstract class ClientBaseClass extends VirtualMethodScope {
    private HashMap virtualMethods = new HashMap();
    
    final void addMethod(String methodName, VirtualMethod method) {
        virtualMethods.put(methodName, method);
    }
    
    protected final void call(String methodName) {
        VirtualMethod method = (VirtualMethod)virtualMethods.get(methodName);
        method.call();
    }
    
}

The ClientBaseClass's addMethod() has "friendly" access, and is therefore visible only within the vault package. This effectively restricts anyone from calling addMethod(), except for the ServerBaseClass listed below. Also, note that call() is protected, so that Client (which does not reside in the vault package) can call its own call() method. call() is also final, meaning we don't trust the Client developer to modify it. But the Client developer can still expose a public method that calls call()!

// ********* ServerBaseClass ********
package vault;
public abstract class ServerBaseClass extends VirtualMethodScope {
    
    final protected void addMethod(ClientBaseClass client, String methodName,
VirtualMethod method) {
        client.addMethod(methodName, method);
    }
    
}

ServerBaseClass's addMethod() is protected, so that Server (which does not reside in the vault package) can call its own addMethod() method. Declaring this method final prevents it from being overridden with less restrictive access. Within the scope of the working package (the package of Client and Server), only Client, Server, and their descendents can access this addMethod() method:

// ********* Client ********
public class Client extends vault.ClientBaseClass {        // NOT in the vault
package!!!
    public void demonstrateAccess(String methodName) {
        call(methodName);
    }
    
}
// ********* Server ********
public class Server extends vault.ServerBaseClass {        // NOT in the vault
package!!!
    
    private void shakeRattleAndRoll() {
        System.out.println("SHAKE ... RATTLE AN' ROLL!!!");
    }
    
    private class ShakeRattleAndRoll extends VirtualMethod {
        protected void call() {
            shakeRattleAndRoll();
        }
    }
    
    public Client getClient() {
        Client client = new Client();
        addMethod(client, "shakeRattleAndRoll", new ShakeRattleAndRoll());
        return client;
    }
    
}

With this pattern's improved version, you can easily customize both Client and Server behavior, simply by extending Server:

// ********* ExtendedServer ********
public class ExtendedServer extends Server {
    
    private void getUpAndBoogy() {
        System.out.println("GET UP... AND BOOOOOGGYYYYY!!!");
    }
    
    private class GetUpAndBoogy extends VirtualMethod {
        protected void call() {
            getUpAndBoogy();
        }
    }
    
    public Client getClient() {
        Client client = super.getClient();
        addMethod(client, "getUpAndBoogy", new GetUpAndBoogy());
        return client;
    }
    
}

Infinite resolution

Inner classes may extend regular (non-inner) classes, and the inner child may be private even though the parent is public. This permits access to public interface methods, while restricting access to the implementation of that interface. Therefore, a "server" class may selectively offer "client" classes instances of the server's private, inner implementation of that public interface, thereby granting access to certain server's private fields and methods. The resolution of this technique is essentially infinite -- any client class in any package may be granted or denied access to the server's sensitive private methods.

Wally Flint is the lead engineer for a company developing linguistic and multimedia applications. He earned a BSEE from the University of Michigan and a master's degree in international business from The American Graduate School of International Management.

Learn more about this topic

1 2 Page 2
Page 2 of 2