简体   繁体   中英

Is it possible create a single dynamic proxy that can add functionality to any concrete class?

I'll give a brief overview of my goals below just in case there are any better, alternative ways of accomplishing what I want. This question is very similar to what I need, but not quite exactly what I need. My question...

I have an interface:

public interface Command<T> extends Serializable {}

..plus an implementation:

public class EchoCommand implements Command<String> {
    private final String stringToEcho;

    public EchoCommand(String stringToEcho) {
        this.stringToEcho = stringToEcho;
    }

    public String getStringToEcho() {
        return stringToEcho;
    }
}

If I create another interface:

public interface AuthorizedCommand {
    String getAuthorizedUser();
}

..is there a way I can implement the AuthorizedCommand interface on EchoCommand at runtime without knowing the subclass type?

public <C extends Command<T>,T> C authorize(C command) {
    // can this be done so the returned Command is also an
    // instance of AuthorizedCommand?
    return (C) theDecoratedCommand;
}

The why... I've used Netty to build myself a very simple proof-of-concept client / server framework based on commands. There's a one-to-one relationship between a command, shared between the client and server, and a command handler. The handler is only on the server and they're extremely simple to implement. Here's the interface.

public interface CommandHandler<C extends Command<T>,T> {
    public T execute(C command);
}

On the client side, things are also extremely simple. Keeping things simple in the client is the main reason I decided to try a command based API. A client dispatches a command and gets back a Future. It's clear the call is asynchronous plus the client doesn't have deal with things like wrapping the call in a SwingWorker . Why build a synchronous API against asynchronous calls (anything over the network) just to wrap the synchronous calls in an asynchronous helper methods? I'm using Guava for this.

public <T> ListenableFuture<T> dispatch(Command<T> command)

Now I want to add authentication and authorization. I don't want to force my command handlers to know about authorization, but, in some cases, I want them to be able to interrogate something with regards to which user the command is being executed for. Mainly I want to be able to have a lastModifiedBy attribute on some data.

I'm looking at using Apache Shiro, so the obvious answer seems to be to use their SubjectAwareExecutor to get authorization information into ThreadLocal , but then my handlers need to be aware of Shiro or I need to abstract it away by finding some way of mapping commands to the authentication / authorization info in Shiro.

Since each Command is already carrying state and getting passed through my entire pipeline, things are much simpler if I can just decorate commands that have been authorized so they implement the AuthorizedCommand interface. Then my command handlers can use the info that's been decorated in, but it's completely optional.

if(command instanceof AuthorizedCommand) {
    // We can interrogate the command for the extra meta data
    // we're interested in.
}

That way I can also develop everything related to authentication / authorization independent of the core business logic of my application. It would also (I think) let me associate session information with a Netty Channel or ChannelGroup which I think makes more sense for an NIO framework, right? I think Netty 4 might even allow typed attributes to be set on a Channel which sounds well suited to keeping track of things like session information (I haven't looked into it though).

The main thing I want to accomplish is to be able to build a prototype of an application very quickly. I'd like to start with a client side dispatcher that's a simple map of command types to command handlers and completely ignore the networking and security side of things. Once I'm satisfied with my prototype, I'll swap in my Netty based dispatcher (using Guice) and then, very late in the development cycle, I'll add Shiro.

I'd really appreciate any comments or constructive criticism. If what I explained makes sense to do and isn't possible in plain old Java, I'd consider building that specific functionality in another JVM language. Maybe Scala?

You could try doing something like this:

Java: Extending Class At Runtime

At runtime your code would extend the class of the Command to be instantiated and implement the AuthorizedCommand interface. This would make the class an instance of AuthorizedCommand while retaining the original Command class structure.

One thing to watch for, you wouldn't be able to extend any classes with the "final" keyword.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM