/* * 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.event; import net.jini.config.Configuration; import net.jini.core.event.EventRegistration; import net.jini.core.event.RemoteEventListener; import net.jini.core.lease.Lease; import net.jini.core.lease.LeaseDeniedException; import org.rioproject.event.EventDescriptor; import org.rioproject.event.EventHandler; import org.rioproject.impl.service.LandlordLessor; import org.rioproject.impl.service.LeasedListManager; import org.rioproject.impl.service.ServiceResource; import org.rioproject.impl.watch.StopWatch; import org.rioproject.impl.watch.Watch; import org.rioproject.impl.watch.WatchDataSourceRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.rmi.MarshalledObject; import java.rmi.RemoteException; import java.util.NoSuchElementException; /** * The EventHandler is an abstract class that handles the basic event plumbing. * The EventHandler sets up a LandLordLessor for the event type and creates * leased event registrations for event registrants * * @author Dennis Reedy */ public abstract class AbstractEventHandler implements EventHandler { protected EventDescriptor descriptor; protected LandlordLessor landlord; protected int sent = 0; protected long sktime, ektime; protected float tmp; protected StopWatch responseWatch = null; protected WatchDataSourceRegistry watchRegistry = null; protected LeasedListManager resourceMgr; public static final String RESPONSE_WATCH = "Response Time - "; protected long t0, t1, sendTime; static final Logger logger = LoggerFactory.getLogger(EventHandler.class); /** * The sequence number is an increasing value that will act as a hint to the * number of occurrences of an event type. The sequence number should differ * if and only if the RemoteEvent objects are a response to different * events. The sequence number should be increased only after an event has * been sent */ protected long sequenceNumber = 0; /** * Use this constructor to create an EventHandler for a given * EventDescriptor with a LandlordLessor created with default values used * for LeasePeriodPolicy * * @param descriptor EventDescriptor for the event to handle * * @throws IOException If a landlord lease manager cannot be created */ public AbstractEventHandler(EventDescriptor descriptor) throws IOException { this(descriptor, net.jini.config.EmptyConfiguration.INSTANCE); } /** * Use this constructor to create an EventHandler for a given * EventDescriptor with a LandlordLessor created with specific values used * for LeaseDurationPolicy. If either of the values specified for the lease * duration are null defaults will be used to create the LandlordLessor. * * @param descriptor EventDescriptor for the event to handle * @param config A Configuration object * * @throws IOException If a landlord lease manager cannot be created */ public AbstractEventHandler(EventDescriptor descriptor, Configuration config) throws IOException { if(descriptor == null) throw new IllegalArgumentException("descriptor is null"); this.descriptor = descriptor; resourceMgr = new LeasedListManager(); landlord = new LandlordLessor(config); landlord.addLeaseListener(resourceMgr); } /** * Registers a RemoteEventListener for this event type. This method will be * delegated from the EventProducer#register method invocation <br> * * @param eventSource The event source * @param listener RemoteEventListener * @param handback MarshalledObject * @param duration Requested EventRegistration lease <br> * @return EventRegistration <br> * * @throws LeaseDeniedException If the lease manager denies the lease */ public EventRegistration register(Object eventSource, RemoteEventListener listener, MarshalledObject handback, long duration) throws LeaseDeniedException { EventRegistrationResource resource = new EventRegistrationResource(listener, handback); ServiceResource sr = new ServiceResource(resource); Lease lease = landlord.newLease(sr, duration); EventRegistration registration = new EventRegistration(descriptor.eventID, eventSource, lease, sequenceNumber); if(logger.isTraceEnabled()) logger.trace("Total registrations for {} {}", descriptor.toString(), getRegistrantCount()); return (registration); } /** * Terminates this EventHandler. This causes all event registrant leases to * be cancelled , and if any watches have been created those watches will be * destroyed */ public void terminate() { landlord.removeAll(); landlord.stop(true); destroyWatch(); } /** * Create a response time watch for this EventHandler, which will track the * response time for event consumers, measured by how long each fire() * invocation takes * * @param watchRegistry The WatchRegistry to register the StopWatch */ public void createWatch(WatchDataSourceRegistry watchRegistry) { responseWatch = new StopWatch(RESPONSE_WATCH + descriptor.toString()); if(watchRegistry == null) return; this.watchRegistry = watchRegistry; watchRegistry.register(responseWatch); } /** * Destroys the response time watch. Once this method is called the watches * will be rendered useless */ public void destroyWatch() { if(watchRegistry != null) { watchRegistry.deregister(responseWatch); } if(responseWatch != null) { try { responseWatch.getWatchDataSource().clear(); responseWatch.getWatchDataSource().close(); } catch(RemoteException e) { logger.error("Destroying Watches", e); } } responseWatch = null; } /** * Get the response time watch for this EventHandler * * @return The response time StopWatch. If the watch was not created this * method returns null */ public Watch getWatch() { return (responseWatch); } /** * Gets the total number of ServiceResource instances contained by the * LandlordLessor used by this EventHandler * * @return The registrant count */ public int getRegistrantCount() { return (landlord.total()); } /** * Used to get the next <code>ServiceResource</code> from a * <code>LandlordLessor</code> * * @return The next <code>ServiceResource</code> contained by the * <code>LandlordLessor</code>. If there are no * <code>ServiceResource</code> instances available in the * <code>LandlordLessor</code> then a value a null is returned */ protected ServiceResource getNextServiceResource() { ServiceResource sr = null; try { while (true) { sr = resourceMgr.getNext(); if(sr == null) break; if(!landlord.ensure(sr)) { if(logger.isTraceEnabled()) logger.trace("Could not ensure resource lease for {}", sr); resourceMgr.removeResource(sr); landlord.remove(sr); } else { break; } } } catch(NoSuchElementException e) { if(logger.isTraceEnabled()) logger.trace("No ServiceResource instances"); } return (sr); } /** * Convenience method to print statistics for every thousand events sent. * This method will only print result if the * <code>-Dorg.rioproject.debug</code> flag is set */ protected void printStats() { if(!logger.isTraceEnabled()) return; if(sent == 0) sktime = System.currentTimeMillis(); int m = sent % 1000; if(m == 0 && sent > 0) { ektime = System.currentTimeMillis(); tmp = (ektime - sktime) / 1000.f; logger.trace("Sent [{}]]\t[1000/{}]\t[{}/Second]", sent, tmp, (1000.f/tmp)); sktime = System.currentTimeMillis(); } } /** * Container class for event registration objects that are created and * behave as the resource that is being leased and controlled by the * ServiceResource */ protected static class EventRegistrationResource { private RemoteEventListener listener; private MarshalledObject handback; public EventRegistrationResource(RemoteEventListener listener, MarshalledObject handback) { this.listener = listener; this.handback = handback; } /** * Returns the event listener. * * @return The event listener */ public RemoteEventListener getListener() { return (listener); } /** * Returns the handback object. * * @return The handback object */ public MarshalledObject getHandback() { return (handback); } } }