Server-Side Command or True RTTI Killer

Discussions

J2EE patterns: Server-Side Command or True RTTI Killer

  1. Server-Side Command or True RTTI Killer (10 messages)

    I was faced recently with the same problem as yours.

    I needed to:

       - process a collection of subclasses
         using a common interface avoiding
         overloading
       - the action code should be in the server-side
         classes not in the client-side value object subclasses
       - I wanted to get rid of the "if/instanceof" structure


    The solution turned out to be rather cumbersome (but it works!):



    CLIENT-SIDE VALUE OBJECTS (command objects):

    These classes follow the Command pattern but delegating
    the action to a server-side object.

    public abstract class Order
    {
        ....
        abstract void processOrder(OrderProcessor op);
    }


    public final class AddOrder extends Order
    {
       ....
       void processOrder(OrderProcessor op)
       {
          op.processOrder(this);
       }

    }

    public final class MoveOrder extends Order
    {
       ....
       void processOrder(OrderProcessor op)
       {
          op.processOrder(this);
       }

    }



    SERVER SIDE CLASSES:

    The server side classes consiste of a package-scope interface
    that declares de OrderProcessor interface.

    The OrderProcessor implementation is a private object
    inside the OrderBroker (maybe an EJB).
    The OrderBroker presents an "immutable" interface out to the client.

    (package-scope)

    interface OrderProcessor
    {
       void processOrder(AddOrder o);
       
       void processOrder(MoveOrder o);
       
    }

    // server-side command broker
    public final class OrderBroker
    {
       // command executor
       private OrderProcessor op = new OrderProcessor()
       {
          public void processOrder(AddOrder o)
          {
             System.out.println("Processing "+o);
          }

          public void processOrder(MoveOrder o)
          {
             System.out.println("Processing "+o);
          }
       };
        
        
       // IMMUTABLE INTERFACE METHOD
       
       public void processOrders(Order[] o)
       {
          for (int i = 0; i < o.length; i++)
        {
           o[i].processOrder(op);
        }
       }


    }



    CLIENT CODE:

    public class Client
    {

        public static void main(String[] args)
        {
           Order o1 = new AddOrder();
           Order o2 = new MoveOrder();
           
           OrderBroker broker = new OrderBroker();
           
           broker.processOrders(new Order[]{o1, o2});
        }
    }

    Threaded Messages (10)

  2. Hi Agusti. Thanks for sharing the pattern.

    I have several problems with this pattern:

    - It's not a command pattern. The functionality is deferred to a different class (OrderProcessor). All the processOrder method of the "command" does is invoke this method. You might as well use the OrderProcessor directly and avoid this meaningless indirection. Besides, if you implement all these methods the same way, why not put them in the abstract superclass?

    - repeated method declaration in the OrderProcessor interface. This gets around RTTI, but completely the wrong way IMHO. You might as well just use different names for each method. The whole idea in having a common base class is that you only declare the method once for that base class, and then when other orders are added to the system you don't need to change your order processor.

    I think a better solution would be to load some sort of "command handler" for each command, which would enable polymorphic handling of commands. The mapping between commands and handlers can be static (e.g., handler class name can be fetched from command) or dynamic (e.g., a hashtable is populated with the mapping at start-up).

    Gal
  3. It's just visitor pattern from GOF. Nodes are diiferent types of orders and visitor - OrderProcessor.
    So why it's new pattern. Next time before posting RTFM.
  4. Hey Giedrius you DMF, you should RTFM.
  5. What is DMF?
  6. Whats this RTFM?
  7. Server-Side Command or True RTTI Killer[ Go to top ]

    RTFM = Read the Friggin' Manual
    DMF ?= Dumb Mother Fudgecake

    Edited for a family audience :)
  8. You've got it Joe!
  9. clear it out[ Go to top ]

    The idea is fine but the implementation is not.

    This is probably what remains after refactoring some time:

    add a method perform(Command) to your ejb; the implementation calls back to the command, passing itself as a kind of execution context:

    BeanImpl
    {

    }

    Command is abstract and has one method perform(Object target)
  10. clear it out - the complete post[ Go to top ]

    Add a method perform(Command) to your ejb; the implementation calls back to the command, passing itself as a kind of execution context:

    BeanImpl
    {
       perform(Command command)
       {
          command.perform(this);
       }
    }

    Command is abstract and has one method perform(Object execution_context). The subclasses "know" which context to expect, so they cast it, and use it to perform their work, remotely:

    AddUsers extends Command
    {
        private Group group;
        private Collection users;
        perform(Object execution_context)
        {
            BeanItf ejb = (BeanItf)execution_context;
            Iterator user = users.iterator();
            while (users.hasNext())
            {
               Object user = users.next();
               ejb.addUser(user);
               ejb.assignUserToGroup(user,group);
            }
        }
    }

    The cool thing is: the code in the command is programmed using the same "api" as the client, but it skips many remote calls, by executing the command logic inside the ejb. This also means it's a single transaction (if perform is transaction required).

    I think this technique is very important to be able to stablize your ejb interfaces: define a basic set of "simple" methods, and program more complex operations as Commands.
  11. clear it out - the complete post[ Go to top ]

    This is indeed a nice use of the Command pattern. It is widely documented and Dieter explained the main advantages well. I want to point out some of the disadvantages:

    - Client code has to be deployed in server unless you want to rely on remote class loading, which I think is a bad idea: It poses a security risk (dispite of Java's secure class loading); It fills the server's VM up with client specific classes; And there is no simple way to avoid conflicts between different client's .class files (except loading each with a different class loader, which is highly expensive).

    - If the client code deployed on the server uses server-internal classes (like local interfaces of entities, utility classes available on the server, etc) they have to also be available on the client's VM, which causes undesirable dependencies. But using server-internal classes are one of the advantages of this pattern.


    These problems cause a strong two-way coupling between the client and the server. If this has a potential of causing problems in your project, you can use a slightly different approach: seperate commands into "command descriptor" client objects and "command handler" server objects. The handler can be looked up by the type of descriptor (for instance, from a static hashmap loaded on init time). The command descriptor is a pure client class, with no references to server-level objects. The handler is a server object. The client doesn't need to know it, and the server can change it's implementation without affecting the client. This solution reduces the dependency to one-way (server depends on client's command descriptor, which means server knows clients usecases at some level), which is neccesary with this pattern anyway unless you allow remote class loading.

    Gal