/* * Copyright 2008 the original author or authors. * Copyright 2005 Sun Microsystems, Inc. * * 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.sla; import com.sun.jini.admin.DestroyAdmin; import net.jini.admin.Administrable; import org.rioproject.servicebean.ServiceBeanManager; import org.rioproject.opstring.OperationalStringException; import org.rioproject.sla.SLA; import org.rioproject.watch.Calculable; import org.rioproject.watch.ThresholdType; import org.rioproject.watch.ThresholdValues; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.rmi.RemoteException; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * The RedeployPolicyHandler will redeploy a service based on declared * thresholds. * * @author Dennis Reedy */ public class RedeployPolicyHandler extends SLAPolicyHandler { /** The description of the SLA Handler */ private static final String description = "Redeploy Policy Handler"; /** Dampening value for upper thresholds being crossed */ private long upperThresholdDampeningTime; /** Dampening value for lower thresholds being crossed */ private long lowerThresholdDampeningTime; /** The Timer to use for scheduling a redeploy task */ private Timer taskTimer; /** The RedeployTask for process redeploy */ private RedeployTask redeployTask; /** Actions that indicate status of a redeploy request */ enum Action { REDEPLOY_PENDING, REDEPLOY_FAILURE, REDEPLOY_SUCCEEDED } /** Logger for this component */ static Logger logger = LoggerFactory.getLogger("org.rioproject.sla"); /** * Construct a RedeployPolicyHandler * * @param sla The SLA for the RedeployPolicyHandler */ public RedeployPolicyHandler(SLA sla) { super(sla); taskTimer = new Timer(true); } /** * Override parent's method to return description for this SLA Handler * * @return The descriptive attribute for this SLA Handler */ @Override public String getDescription() { return (description); } /** * Override parent's method to shutdown timer */ @Override public void disconnect() { if(taskTimer != null) taskTimer.cancel(); super.disconnect(); } @Override public void setSLA(SLA sla) { super.setSLA(sla); upperThresholdDampeningTime = (getSLA().getUpperThresholdDampeningTime()==0?1000: getSLA().getUpperThresholdDampeningTime()); lowerThresholdDampeningTime = (getSLA().getLowerThresholdDampeningTime()==0?1000: getSLA().getLowerThresholdDampeningTime()); } @Override public void notify(Calculable calculable, ThresholdValues thresholdValues, ThresholdType type) { if(logger.isDebugEnabled()) { String status = (type == ThresholdType.BREACHED? "breached":"cleared"); logger.debug("RedeployPolicyHandler [{}]: Threshold {}] {} value [{}\n] low [{}] high [{}]", getID(), calculable.getId(), status, calculable.getValue(), thresholdValues.getCurrentLowThreshold(), thresholdValues.getCurrentHighThreshold()); } if(type == ThresholdType.BREACHED) { double tValue = calculable.getValue(); if(tValue > thresholdValues.getCurrentHighThreshold()) { doRedeploy(upperThresholdDampeningTime, "upper"); } else { doRedeploy(lowerThresholdDampeningTime, "lower"); } /* Threshold has been cleared */ } else { if(redeployTask!=null) { redeployTask.cancel(); redeployTask = null; } } sendSLAThresholdEvent(calculable, thresholdValues, type); } /* * Determine whether a RedeployTask should be created based on the * delay value provided, or to relocate immediately */ private void doRedeploy(long delay, String type) { if(delay > 0) { redeployTask = new RedeployTask(); long now = System.currentTimeMillis(); if(logger.isDebugEnabled()) logger.debug("[{}] RedeployPolicyHandler [{}]: Schedule redeploy task in [{}] millis", context.getServiceElement().getName(), getID(), delay); try { taskTimer.schedule(redeployTask, new Date(now+delay)); } catch(IllegalStateException e) { logger.warn("Force disconnect of ["+context.getServiceElement().getName()+"] RedeployPolicyHandler", e); disconnect(); } } else { logger.info("[{}] RedeployPolicyHandler [{}]: no {} dampener, perform redeploy", context.getServiceElement().getName(), getID(), type); doRedeploy(); } } /** * Perform the redeploy */ void doRedeploy() { notifyListeners(new SLAPolicyEvent(this, getSLA(), Action.REDEPLOY_PENDING.name())); ServiceBeanManager mgr = context.getServiceBeanManager(); try { mgr.getOperationalStringManager().redeploy(context.getServiceElement(), mgr.getServiceBeanInstance(), false, true, 0, null); } catch (OperationalStringException e) { notifyListeners(new SLAPolicyEvent(this, getSLA(), Action.REDEPLOY_FAILURE.name())); if(!e.isManaged()) { logger.warn("Attempt to redeploy service [{}] failed, it is not under management control. Terminating the service.", context.getServiceElement().getName()); try { Administrable admin = (Administrable)mgr.getServiceBeanInstance().getService(); DestroyAdmin dAdmin = (DestroyAdmin) admin.getAdmin(); dAdmin.destroy(); } catch(Exception ex) { logger.error("Unable to destroy service ["+context.getServiceElement().getName()+"] ", ex); } } else { getSLA().resetHighThreshold(); getSLA().resetLowThreshold(); } } catch(RemoteException e) { logger.warn("Attempt to redeploy service failed [{}: {}]", e.getClass().getName(), e.getLocalizedMessage()); notifyListeners(new SLAPolicyEvent(this, getSLA(), Action.REDEPLOY_FAILURE.name())); getSLA().resetHighThreshold(); getSLA().resetLowThreshold(); } } /** * The RedeployTask is used to schedule a process redeploy be performed at * some time in the future. */ class RedeployTask extends TimerTask { public void run() { doRedeploy(); } } }