Title: RE: [jdjlist] Command design pattern

Often a command pattern is used to execute some type of utility functions around the
execute() or to implement a system wide re-try strategy on a distributed system.  Here is an example of a re-try strategy using a command pattern in an RMI system.

Greg

http://www.HotSciFi.com


package hr.shared.rmi;

import hr.shared.util.*;

import java.rmi.*;
import java.rmi.server.*;

/**
 * Adopted from the code by William Grosso, author of Java RMI
 * 10/17/2001
 *
 * http://www.onjava.com/pub/a/onjava/2001/10/17/rmi.html
 * oreillynet.com Copyright &copy 2000 O'Reilly & Associates, Inc.
 */

public abstract class AbstractRemoteMethodCall {
    public Object makeCall() throws HRException, Exception {
        Object result = null;

        RetryStrategy strategy = getRetryStrategy();
        while (strategy.shouldRetry()) {
            HRUtil.log("----->ENVOKING REMOTE METHOD");
            Remote remoteObject = getRemoteObject();
            if (null==remoteObject) {
                throw new HRException("remote object is null", 701);
            }

            try {
                result = performRemoteCall(remoteObject);
                HRUtil.log("----->REMOTE METHOD RESULT:" + result);
                break;
            } catch (RemoteException remoteException) {
                try {
                    strategy.remoteExceptionOccurred();
                } catch (RetryException retryException) {
                    handleRetryException(remoteObject);
                }
            }
        }              
        return result;
    }

    /*
      The next 4 methods define the core behavior. Of these, two must
      be implemented by the subclass (and so are left abstract). The
      remaining three can be altered to provide customized retry handling.
    */

    /**
       getRemoteObject is a template method which should, in most cases,
       return the stub.
    */

    protected abstract Remote getRemoteObject() throws HRException;

    /**
       performRemoteCall is a template method which actually makes the remote
       method invocation.
    */
    protected abstract Object performRemoteCall(Remote remoteObject) throws RemoteException, Exception;


    protected RetryStrategy getRetryStrategy() {
        return new AdditiveWaitRetryStrategy();
    }
 
    //simply re-throw the internal exception as an application exception
    protected void handleRetryException(Remote remoteObject) throws HRException {
        throw new HRException("Repeated attempts to communicate with " + remoteObject + " failed.", 702);
    }
}



package hr.shared.rmi;

import hr.shared.util.*;

/**
        The most commonly used retry strategy; it extends the waiting
        period by a constant amount with each retry.

        Note that the default version of this (e.g. the one with a
        zero argument constructor) will make 3 calls and wind up waiting
        approximately 11 seconds (zero wait for the first call, 3 seconds
        for the second call, and 8 seconds for the third call). These
        wait times are pretty small, and are usually dwarfed by socket
        timeouts when network difficulties occur anyway.
*/

public class AdditiveWaitRetryStrategy extends RetryStrategy {
        public static final long STARTING_WAIT_TIME = 3000;
        public static final long WAIT_TIME_INCREMENT = 5000;

        private long _currentTimeToWait;
        private long _waitTimeIncrement;
       
        public AdditiveWaitRetryStrategy () {
                this(DEFAULT_NUMBER_OF_RETRIES , STARTING_WAIT_TIME, WAIT_TIME_INCREMENT);
        }

        public AdditiveWaitRetryStrategy (int numberOfRetries, long startingWaitTime, long waitTimeIncrement) {
                super(numberOfRetries);
                _currentTimeToWait = startingWaitTime;
                _waitTimeIncrement = waitTimeIncrement;
        }

        protected long getTimeToWait() {
                long returnValue = _currentTimeToWait;
                _currentTimeToWait += _waitTimeIncrement;
                return returnValue;
        }
}



package hr.shared.rmi;

import hr.shared.util.*;

/**
        Abstract base class for retry strategies.
*/

public abstract class RetryStrategy {
    public static final int DEFAULT_NUMBER_OF_RETRIES = 3;
    private int _numberOfTriesLeft;

    public RetryStrategy() {
        this(DEFAULT_NUMBER_OF_RETRIES);
    }

    public RetryStrategy(int numberOfRetries){
        _numberOfTriesLeft = numberOfRetries;
    }

    public boolean shouldRetry() {
        return (0 < _numberOfTriesLeft);
    }

    public void remoteExceptionOccurred() throws RetryException {
        _numberOfTriesLeft --;
        if (!shouldRetry()) {
            HRUtil.log("----->GIVING UP...");
            throw new RetryException();
        }
        waitUntilNextTry();
    }

    protected abstract long getTimeToWait();

    private void waitUntilNextTry() {
        HRUtil.log("-----> RMI FAILED. WAITING TO RETRY...");
        long timeToWait = getTimeToWait();
        try {
            Thread.sleep(timeToWait );
        }
        catch (InterruptedException ignored) {}
    }
}


//////////////////////////////2 different command objects////////////////

package hr.shared.rmi;

import hr.shared.util.*;
import hr.shared.entity.*;
import hr.shared.entity.pk.*;
import hr.server.db.*;

import java.rmi.*;
import java.rmi.server.*;

public class CreateDepartment extends AbstractRemoteMethodCall {

    private HRDatabaseInterface hrDb;
    private Department entity;

    public CreateDepartment(HRDatabaseInterface hrDb, Department entity) {
        this.hrDb = hrDb;
        this.entity = entity;
    }

    protected Remote getRemoteObject() throws HRException {
        return (Remote) hrDb;
    }

    protected Object performRemoteCall(Remote remoteObject) throws RemoteException, Exception {
        HRDatabaseInterface hrDbInstance = (HRDatabaseInterface) remoteObject;
        return hrDbInstance.createDepartment(entity);
    }
}

package hr.shared.rmi;

import hr.shared.util.*;
import hr.shared.entity.*;
import hr.shared.entity.pk.*;
import hr.server.db.*;

import java.rmi.*;
import java.rmi.server.*;

public class RemoveDepartment extends AbstractRemoteMethodCall {

    private HRDatabaseInterface hrDb;
    private Department entity;

    public RemoveDepartment(HRDatabaseInterface hrDb, Department entity) {
        this.hrDb = hrDb;
        this.entity = entity;
    }

    protected Remote getRemoteObject() throws HRException {
        return (Remote) hrDb;
    }

    protected Object performRemoteCall(Remote remoteObject) throws RemoteException, Exception {
        HRDatabaseInterface hrDbInstance = (HRDatabaseInterface) remoteObject;
        return hrDbInstance.removeDepartment(entity);
    }
}


-----Original Message-----
From: jayaraman sureshkumar [mailto:[EMAIL PROTECTED]]
Sent: Tuesday, June 18, 2002 3:34 AM
To: JDJList
Subject: [jdjlist] Command design pattern


Hello,

I need to know a simple example explaining the subject design pattern in a
nut shell.. please help..

Thanks

Suresh

_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com/intl.asp.


To change your membership options, refer to:
http://www.sys-con.com/java/list.cfm

To change your membership options, refer to:
http://www.sys-con.com/java/list.cfm

Reply via email to