/* * Copyright to 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.sla; import net.jini.config.Configuration; import net.jini.config.ConfigurationException; import net.jini.config.EmptyConfiguration; import org.rioproject.config.Constants; import org.rioproject.impl.watch.SettableThresholdListener; import org.rioproject.impl.watch.ThresholdManager; import org.rioproject.servicebean.ServiceBeanContext; import org.rioproject.event.EventHandler; import org.rioproject.net.HostUtil; import org.rioproject.sla.SLA; import org.rioproject.sla.SLAThresholdEvent; import org.rioproject.watch.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; /** * A SLAPolicyHandler handles thresholds for a ThresholdWatch, registering to a * ThresholdManager. If a threshold is crossed (breached or cleared), the * SLAPolicyHandler will fire a SLAThresholdEvent using an EventHandler provided * * The SLAPolicyHandler should be extended to provide logic on how to process * specific policy (if-then-else logic) on how to manage SLA Thresholds * produced by ThresholdWatch instantiations * * @author Dennis Reedy */ public class SLAPolicyHandler implements SettableThresholdListener { /** The SLA */ private SLA mySLA; /** Event source object */ protected Object eventSource; /** ServiceBeanContext for the ServiceBean */ protected ServiceBeanContext context; /** EventHandler for SLAThresholdEvent dispatching */ private EventHandler eventHandler; /** The ThresholdManager the SLA is for */ protected ThresholdManager thresholdManager; /** Flag which indicates the SLAPolicyHandler has initialized */ protected boolean initialized=false; private String name; /** Collection of SLAPolicyEventListener */ private final List<SLAPolicyEventListener> listeners = new ArrayList<SLAPolicyEventListener>(); /** The description of the SLA Handler */ private String description = "Default Policy Handler"; /** Host address of the compute resource */ private String hostAddress; private final BlockingQueue<SLAThresholdEvent> eventQ = new LinkedBlockingQueue<SLAThresholdEvent>(); private ExecutorService executor; /** A Logger for this component */ static Logger logger = LoggerFactory.getLogger(SLAPolicyHandler.class); /** * Construct a SLAPolicyHandler * * @param sla The SLA for the SLAPolicyHandler */ public SLAPolicyHandler(final SLA sla) { mySLA = sla; try { hostAddress = HostUtil.getHostAddressFromProperty(Constants.RMI_HOST_ADDRESS); } catch(UnknownHostException e) { logger.error("Getting Host Address", e); hostAddress="unknown"; } } /** * Prepare the SLAPolicyHandler for processing. The method will only * set these values if the SLAPolicyHandler has not been initialized before * * @param eventSource The object to be used as the remote event source * @param eventHandler Handler which sends events * @param context The ServiceBeanContext * * @throws IllegalArgumentException if any of the parameters are null */ public void initialize(final Object eventSource, final EventHandler eventHandler, final ServiceBeanContext context) { if(initialized) { logger.trace("[{}] {} [{}] already initialized", getName(), getClass().getName(), getID()); return; } if(eventSource==null) throw new IllegalArgumentException("source is null"); if(context==null) throw new IllegalArgumentException("context is null"); setName(context.getServiceElement().getName(), context.getServiceElement().getServiceBeanConfig().getInstanceID()); //this.proxy = proxy; this.eventSource = eventSource; this.eventHandler = eventHandler; this.context = context; executor = Executors.newSingleThreadExecutor(); executor.execute(new SLAThresholdEventTask()); initialized=true; } /** * Get the source property * * @return The Object used as the event source */ @SuppressWarnings("unused") protected Object getEventSource() { return(eventSource); } /** * Get the description * * @return String The descriptive attribute for this SLA Handler */ public String getDescription() { return(description); } @SuppressWarnings("unused") public void setDescription(String description) { this.description = description; } /** * Set or update the SLA * * @param sla The SLA */ public void setSLA(final SLA sla) { if(sla==null) throw new IllegalArgumentException("sla is null"); mySLA = sla; if(thresholdManager!=null) thresholdManager.setThresholdValues(mySLA); } /** * Get the SLA * * @return The SLA that the SLAPolicyHandler has been constructed with */ public SLA getSLA() { return(mySLA); } /** * Get the Configuration object * * @return The Configuration from the * {@link org.rioproject.servicebean.ServiceBeanContext}. If * the <tt>ServiceBeanContext</tt> is null, return an empty configuration * * @throws ConfigurationException If the configuration cannot be created */ public Configuration getConfiguration() throws ConfigurationException { Configuration config; if(context!=null) config = context.getConfiguration(); else config = EmptyConfiguration.INSTANCE; return(config); } /** * Get the ID of the ThresholdWatch the SLAPolicyHandler is associated to * * @return The identifier (ID) of the ThresholdWatch the SLAPolicyHandler is associated to */ public String getID() { return(mySLA.getIdentifier()); } protected void setName(final String name, final long iID) { if(iID > 0) { this.name = name+":"+iID; } else { this.name = name+":XX"; } } protected String getName() { return (name); } /** * Set the ThresholdManager and connect to the ThresholdManager * * @param thresholdManager The ThresholdManager to connect to */ public void setThresholdManager(final ThresholdManager thresholdManager) { if(thresholdManager==null) throw new IllegalArgumentException("thresholdManager is null"); if(this.thresholdManager!=null && this.thresholdManager.equals(thresholdManager)) return; this.thresholdManager = thresholdManager; this.thresholdManager.setThresholdValues(getSLA()); this.thresholdManager.addThresholdListener(this); logger.debug("[{}] {} [{}]: setThresholdManager() {}", getName(), getClass().getName(), getID(), mySLA.toString()); } /** * @return Get the ThresholdManager */ public ThresholdManager getThresholdManager() { return(thresholdManager); } /** * Disconnect from the ThresholdManager */ public void disconnect() { if(executor!=null) executor.shutdownNow(); if(thresholdManager!=null) thresholdManager.removeThresholdListener(this); eventSource = null; } /** * @see org.rioproject.impl.watch.ThresholdListener#notify */ public void notify(final Calculable calculable, final ThresholdValues thresholdValues, final ThresholdType type) { logger.debug("SLAPolicyHandler.notify() : {}, type={} Value={}, High={}, Low={}", calculable.getId(), type.name().toLowerCase(), calculable.getValue(), mySLA.getCurrentHighThreshold(), mySLA.getCurrentLowThreshold()); if(eventHandler!=null) sendSLAThresholdEvent(calculable, thresholdValues, type); else logger.warn("Unable to send SLAThresholdEvent, eventHandler is null"); } /** * Register for SLAPolicyEvent notifications * * @param listener The SLAPolicyEventListener */ @SuppressWarnings("unused") public void registerListener(final SLAPolicyEventListener listener) { if(listener==null) throw new IllegalArgumentException("listener is null"); synchronized(listeners) { if(!listeners.contains(listener)) { listeners.add(listener); } } } /** * Unregister for SLAPolicyEvent notifications * * @param listener The SLAPolicyEventListener */ @SuppressWarnings("unused") public void unregisterListener(final SLAPolicyEventListener listener) { if(listener==null) throw new IllegalArgumentException("listener is null"); synchronized(listeners) { listeners.remove(listener); } } /** * Notify all registered SLAPolicyEventListener instances * * @param event The SLAPolicyEvent */ protected void notifyListeners(final SLAPolicyEvent event) { synchronized (listeners) { for(SLAPolicyEventListener l : listeners) l.policyAction(event); } } /** * Set up a SLAThresholdEvent and send it * * @param calculable The current metric * @param tValues The current thresholds * @param type The type of threshold event, breached or cleared */ protected void sendSLAThresholdEvent(final Calculable calculable, final ThresholdValues tValues, final ThresholdType type) { try { SLAThresholdEvent event = new SLAThresholdEvent(eventSource, context.getServiceElement(), context.getServiceBeanManager().getServiceBeanInstance(), calculable, mySLA, getDescription(), hostAddress, type); String sType = type.name(); SLAPolicyEvent localEvent = new SLAPolicyEvent(this, mySLA, "THRESHOLD_"+sType); localEvent.setSLAThresholdEvent(event); notifyListeners(localEvent); /* Enqueue the remote notification */ logger.debug("Enqueue SLAThresholdEvent notification for {}", mySLA); eventQ.add(event); } catch(Exception e) { logger.error("Creating a SLAThresholdEvent", e); } } /** * This class is used to notify registered event consumers of a * SLAThresholdEvent */ class SLAThresholdEventTask implements Runnable { public void run() { while (true) { try { SLAThresholdEvent event = eventQ.take(); eventHandler.fire(event); } catch(InterruptedException e) { /* */ break; } catch(Exception e) { logger.warn("Notifying SLAThresholdEvent consumers", e); } } } } }