Package org.rioproject.impl.fdh

Source Code of org.rioproject.impl.fdh.LeaseFaultDetectionHandler$ServiceLeaseManager

/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.impl.fdh;

import com.sun.jini.config.Config;
import net.jini.config.ConfigurationException;
import net.jini.config.ConfigurationProvider;
import net.jini.core.lease.Lease;
import net.jini.security.BasicProxyPreparer;
import net.jini.security.ProxyPreparer;
import org.rioproject.admin.MonitorableService;
import org.rioproject.impl.util.ThrowableUtil;
import org.rioproject.util.TimeUtil;

import java.rmi.RemoteException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The LeaseFaultDetectionHandler is used to monitor services that implement the
* {@link org.rioproject.admin.MonitorableService} interface.
*
* <p>The LeaseFaultDetectionHandler creates a client-side
* {@link net.jini.core.lease.Lease} with the service,
* and attempts to renew the lease based on a configurable lease duration time.
* If the lease cannot be renewed and all retry attempts have failed, the
* LeaseFaultDetectionHandler will notify
* {@link FaultDetectionListener} instances of
* the failure.
* <p>
* Additionally, the LeaseFaultDetectionHandler will register with Lookup
* Services for
* {@link net.jini.core.lookup.ServiceRegistrar#TRANSITION_MATCH_NOMATCH}
* transitions for the service being monitored. If the service is
* adminstratively removed from the network, or the service monitoring lease
* is between lease renewal points and the service has actually been removed
* from the network, the transition will be noted and FaultDetectionListener
* instances will be notified of the failure.
* <p>
* If the service does not implement the
* {@link org.rioproject.admin.MonitorableService} interface, the
* LeaseFaultDetectionHandler will not manage a Lease, but will only create
* the event consumer for Lookup Service TRANSITION_MATCH_NOMATCH transitions.
* <p>
* <b><font size="+1">Configuring LeaseFaultDetectionHandler </font> </b>
* <p>
* This implementation of LeaseFaultDetectionHandler supports
* the following configuration entries; where each configuration entry name is
* associated with the component name
* <code>org.rioproject.impl.fdh.LeaseFaultDetectionHandler</code>.
* <br>
* <br>
* <ul>
* <li><span style="font-weight: bold; font-family: courier
* new,courier,monospace;">leaseDuration </span> <table cellpadding="2"
* cellspacing="2" border="0" style="text-align: left; width: 100%;"> <tbody>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Type: <br>
* </td>
* <td style="vertical-align: top; font-family: monospace;">long</td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Default: <br>
* </td>
* <td style="vertical-align: top;"><code>30*1000 (30 seconds)</code></td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Description: <br>
* </td>
* <td style="vertical-align: top;">The duration of the Lease in milliseconds.
* The Lease renewal time will be calculated to be 75% of the LeaseTime
* attribute</td>
* </tr>
* </tbody> </table></li>
* </ul>
* <ul>
* <li><span style="font-weight: bold; font-family: courier
* new,courier,monospace;">retryCount </span> <table cellpadding="2"
* cellspacing="2" border="0" style="text-align: left; width: 100%;"> <tbody>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Type: <br>
* </td>
* <td style="vertical-align: top;"><code>int</code><br>
* </td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Default: <br>
* </td>
* <td style="vertical-align: top;"><code>3</code></td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Description: <br>
* </td>
* <td style="vertical-align: top;">The number of times to retry connecting to
* the service when renewing the Lease. If the service cannot be reached within
* the retry count specified the service will be determined to be unreachable
* </td>
* </tr>
* </tbody> </table></li>
* </ul>
* <ul>
* <li><span style="font-weight: bold; font-family: courier
* new,courier,monospace;">retryTimeout </span> <table cellpadding="2"
* cellspacing="2" border="0" style="text-align: left; width: 100%;"> <tbody>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Type: <br>
* </td>
* <td style="vertical-align: top;"><code>long</code></td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Default: <br>
* </td>
* <td style="vertical-align: top;"><code>1000 (1 second)</code></td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Description: <br>
* </td>
* <td style="vertical-align: top;">How long to wait between retries (in
* milliseconds). This value will be used between retry attempts, waiting the
* specified amount of time to retry <br>
* </td>
* </tr>
* </tbody> </table></li>
* </ul>
* <ul>
* <li><span style="font-weight: bold; font-family: courier
* new,courier,monospace;">leasePreparer </span> <table cellpadding="2"
* cellspacing="2" border="0" style="text-align: left; width: 100%;"> <tbody>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Type: <br>
* </td>
* <td style="vertical-align: top;"><code>ProxyPreparer</code></td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Default: <br>
* </td>
* <td style="vertical-align: top;">
* <code>new <code>BasicProxyPreparer</code>()</code></td>
* </tr>
* <tr><td style="vertical-align: top; text-align: right; font-weight:
* bold;">Description: <br>
* </td>
* <td style="vertical-align: top;">Preparer for the leases returned when the
* <span style="font-family: monospace;">LeaseFaultDetectionHandler </span>
* invokes the monitor method of a <span style="font-family:
* monospace;">MonitorableService </span></td>
* </tr>
* </tbody> </table></li>
* </ul>
* <br>
* The amount of time it takes for the StandardFaultDetectionListener to
* determine service failure for a service that implements the
* <code>org.rioproject.core.MonitorableService</code> interface is calculated as
* follows :<br>
*
* <pre>
* ((num_retries + 1) * (connectivity_timeout)) + (retry_delay * num_retries)
* </pre>
*
* @author Dennis Reedy
*/
public class LeaseFaultDetectionHandler extends AbstractFaultDetectionHandler {
    public static final long DEFAULT_LEASE_DURATION = 1000 * 60;   
    public static final String LEASE_DURATION_KEY = "leaseDuration";   
    private long leaseDuration = DEFAULT_LEASE_DURATION;   
    /** The proxyPreparer for Lease */
    private ProxyPreparer leasePreparer;   
    /** Component name, used for config and logger */
    private static final String COMPONENT =
        "org.rioproject.impl.fdh.LeaseFaultDetectionHandler";
    /** A Logger */
    static Logger logger = LoggerFactory.getLogger(COMPONENT);

    public void setLeaseDuration(long leaseDuration) {
        this.leaseDuration = leaseDuration;
    }

    public void setLeasePreparer(ProxyPreparer leasePreparer) {
        this.leasePreparer = leasePreparer;
    }

    /**
     * @see FaultDetectionHandler#setConfiguration
     */
    public void setConfiguration(String[] configArgs) {
        if(configArgs == null)
            throw new IllegalArgumentException("configArgs is null");
        try {
            this.configArgs = new String[configArgs.length];
            System.arraycopy(configArgs, 0, this.configArgs, 0, configArgs.length);
           
            this.config = ConfigurationProvider.getInstance(configArgs);
            setLeaseDuration(Config.getLongEntry(config,
                                                 COMPONENT,
                                                 LEASE_DURATION_KEY,
                                                 DEFAULT_LEASE_DURATION,
                                                 0,
                                                 Long.MAX_VALUE));
            setRetryCount(Config.getIntEntry(config,
                                             COMPONENT,
                                             RETRY_COUNT_KEY,
                                             DEFAULT_RETRY_COUNT,
                                             0,
                                             Integer.MAX_VALUE));
            setRetryTimeout(Config.getLongEntry(config,
                                                COMPONENT,
                                                RETRY_TIMEOUT_KEY,
                                                DEFAULT_RETRY_TIMEOUT,
                                                0,
                                                Long.MAX_VALUE));
            setLeasePreparer((ProxyPreparer)config.getEntry(COMPONENT,
                                                            "leasePreparer",
                                                            ProxyPreparer.class,
                                                            new BasicProxyPreparer()));
            if(logger.isTraceEnabled()) {
                StringBuilder buffer = new StringBuilder();
                buffer.append("LeaseFaultDetectionHandler Properties : ");
                buffer.append("lease duration=").append(leaseDuration).append(", ");
                buffer.append("retry count=").append(retryCount).append(", ");
                buffer.append("retry timeout=").append(retryTimeout);
                logger.trace(buffer.toString());
            }
        } catch(ConfigurationException e) {
            logger.error("Setting Configuration", e);
        }
    }   

    /**
     * Override parent's getServiceMonitor() method to create
     * the ServiceLeaseManager
     */
    protected ServiceMonitor getServiceMonitor() throws Exception {
        ServiceMonitor monitor = null;
        if(proxy instanceof MonitorableService) {
            MonitorableService service = (MonitorableService)proxy;
            Lease lease = service.monitor(leaseDuration);
            lease = (Lease)leasePreparer.prepareProxy(lease);
            serviceMonitor = new ServiceLeaseManager(lease);
        } else {
            logger.info("Service ["+proxy.getClass().getName()+"] not an "+
                        "instanceof "+MonitorableService.class.getName()+", "+
                        "ServiceRegistrar.TRANSITION_MATCH_NOMATCH transitions will "+
                        "only be monitored");
        }
        return(monitor);
    }
   
    /**
     * Manage the Lease to the MonitorableService
     */
    class ServiceLeaseManager extends Thread implements ServiceMonitor {
        long leaseTime;
        boolean keepAlive = true;
        Lease lease;

        /**
         * Create a ServiceLeaseManager
         *
         * @param lease The Lease to manage
         */
        ServiceLeaseManager(Lease lease) {
            super("ServiceLeaseManager:"
                  + proxy.getClass().getName()
                  + ":"
                  + System.currentTimeMillis());
            this.lease = lease;
            this.leaseTime = lease.getExpiration() - System.currentTimeMillis();
            setDaemon(true);
            start();
        }

        /**
         * @see AdminFaultDetectionHandler.ServiceMonitor#drop
         */
        public void drop() {           
            interrupt();
        }

        public void interrupt() {
            if(logger.isTraceEnabled())
                logger.trace("Terminating ServiceMonitor Thread");
            try {
                lease.cancel();
            } catch(Exception ignore) {
                /* ignore */
            }
            keepAlive = false;
            super.interrupt();
        }

        /**
         * @see AdminFaultDetectionHandler.ServiceMonitor#verify()
         */
        public boolean verify() {
            if(!keepAlive)
                return (false);
            boolean verified = false;
            try {
                /*
                 * Invoke the service. If the service isnt active we'll get a
                 * RemoteException
                 */
                MonitorableService service = (MonitorableService)proxy;
                service.ping();
                verified = true;
            } catch(RemoteException e) {
                if(logger.isTraceEnabled())
                    logger.trace("RemoteException reaching service, "+
                                  "service cannot be reached");
                keepAlive = false;
            }
            return (verified);
        }

        public void run() {
            while (!interrupted()) {
                if(!keepAlive) {
                    return;
                }
                long leaseRenewalTime = TimeUtil.computeLeaseRenewalTime(leaseTime);
                if(logger.isTraceEnabled())
                    logger.trace("ServiceLeaseManager: Lease renewal wait for ["
                                  + leaseRenewalTime
                                  + "] millis "
                                  + "for "
                                  + proxy.getClass().getName());
                try {
                    sleep(leaseRenewalTime);
                } catch(InterruptedException ie) {
                    /* ignore */
                } catch(IllegalArgumentException iae) {
                    logger.warn("ServiceLeaseManager: sleep time is off : "
                                   + leaseRenewalTime);
                }
                if(lease != null) {
                    try {
                        if(logger.isTraceEnabled())
                            logger.trace("Renew lease for : "
                                          + proxy.getClass().getName());
                        lease.renew(leaseTime);
                    } catch(Exception e) {
                        if(!ThrowableUtil.isRetryable(e)) {
                            keepAlive = false;
                            if(logger.isDebugEnabled())
                                logger.debug(
                                           "Unrecoverable Exception renewing"+
                                           "Lease",
                                           e);
                        }
                        /*
                         * If we failed to renew the Lease we should try and
                         * re-establish comms to the Service and get another
                         * Lease
                         */
                        if(keepAlive) {
                            if(logger.isTraceEnabled())
                                logger.trace("Failed to renew lease to : "
                                              + proxy.getClass().getName()
                                              + ", retry ["
                                              + retryCount
                                              + "] "
                                              + "times, waiting ["
                                              + retryTimeout
                                              + "] millis between "
                                              + "attempts");
                            boolean connected = false;
                            for(int i = 0; i < retryCount; i++) {
                                long t0 = 0;
                                long t1;
                                try {
                                    if(logger.isTraceEnabled())
                                        logger.trace("Attempt to re-establish "+
                                                      "Lease to : "
                                                      + proxy.getClass().getName()
                                                      + ", attempt "
                                                      + "["
                                                      + i
                                                      + "]");
                                    MonitorableService service =
                                        (MonitorableService)proxy;
                                    t0 = System.currentTimeMillis();
                                    this.lease = service.monitor(leaseDuration);
                                    if(logger.isTraceEnabled())
                                        logger.trace("Re-established Lease to : "
                                                      + proxy.getClass().getName());
                                    connected = true;
                                    break;
                                } catch(Exception e1) {
                                    t1 = System.currentTimeMillis();
                                    if(logger.isTraceEnabled())
                                        logger.trace("Invocation attempt ["
                                                      + i
                                                      + "] took ["
                                                      + (t1 - t0)
                                                      + "] "
                                                      + "millis to fail for : "
                                                      + proxy.getClass().getName());
                                    if(retryTimeout > 0) {
                                        try {
                                            sleep(retryTimeout);
                                        } catch(InterruptedException ie) {
                                            /* ignore */
                                        }
                                    }
                                }
                            }
                            if(!connected) {
                                if(logger.isTraceEnabled()) {
                                    if(proxy != null)
                                        logger.trace("Unable to recover Lease to ["
                                                      + proxy.getClass().getName()
                                                      + "], notify "
                                                      + "listeners and exit");
                                    else
                                        logger.trace("Unable to recover Lease to "+
                                                      "[null proxy], "
                                                      + "notify listeners and exit");
                                }
                                notifyListeners();
                                break;
                            }
                        } else {
                            notifyListeners();
                            break;
                        }
                    }
                }
            }
            terminate();
        }
    }
      
}
TOP

Related Classes of org.rioproject.impl.fdh.LeaseFaultDetectionHandler$ServiceLeaseManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.