/* * 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.config.EmptyConfiguration; import net.jini.core.entry.Entry; import net.jini.core.lookup.ServiceID; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceTemplate; import net.jini.discovery.DiscoveryManagement; import net.jini.lease.LeaseRenewalManager; import net.jini.lookup.LookupCache; import net.jini.lookup.ServiceDiscoveryEvent; import net.jini.lookup.ServiceDiscoveryManager; import org.rioproject.impl.client.ServiceDiscoveryAdapter; import org.rioproject.event.EventDescriptor; import org.rioproject.event.RemoteServiceEventListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.rmi.MarshalledObject; /** * A DynamicEventConsumer extends {@link BasicEventConsumer} and provides the * capability to discover when {@link org.rioproject.event.EventProducer} instances join and leave the * network * * @author Dennis Reedy */ public class DynamicEventConsumer extends BasicEventConsumer { private ServiceDiscoveryManager sdm; private LookupCache lCache; private static Logger logger = LoggerFactory.getLogger(DynamicEventConsumer.class); /** * Create a DynamicEventConsumer with an EventDescriptor * * @param edTemplate The EventDescriptor template * @param dMgr The DiscoveryManagement instance * * @throws Exception if the DynamicEventConsumer cannot be created */ public DynamicEventConsumer(final EventDescriptor edTemplate, final DiscoveryManagement dMgr) throws Exception { this(edTemplate, null, dMgr); } /** * Create a DynamicEventConsumer with an EventDescriptor, a * RemoteServiceEventListener and a DiscoveryManagement instance * * @param edTemplate The EventDescriptor template * @param listener The RemoteServiceEventListener * @param dMgr The DiscoveryManagement instance * * @throws Exception if the DynamicEventConsumer cannot be created */ public DynamicEventConsumer(final EventDescriptor edTemplate, final RemoteServiceEventListener listener, final DiscoveryManagement dMgr) throws Exception { this(edTemplate, listener, null, dMgr); } /** * Create a DynamicEventConsumer with an EventDescriptor, a * RemoteServiceEventListener a MarshalledObject handback, a specified lease * duration to be used for all event registrations and a DiscoveryManagement * instance * * @param edTemplate The EventDescriptor template * @param listener The RemoteServiceEventListener * @param handback The MarshalledObject to be used as a handback * @param dMgr The DiscoveryManagement instance * * @throws Exception if the DynamicEventConsumer cannot be created */ public DynamicEventConsumer(final EventDescriptor edTemplate, final RemoteServiceEventListener listener, final MarshalledObject handback, final DiscoveryManagement dMgr) throws Exception { this(edTemplate, listener, handback, dMgr, null); } /** * Create a DynamicEventConsumer with an EventDescriptor, a * RemoteServiceEventListener a MarshalledObject handback, a specified lease * duration to be used for all event registrations and a DiscoveryManagement * instance * * @param edTemplate The EventDescriptor template * @param listener The RemoteServiceEventListener * @param handback The MarshalledObject to be used as a handback * @param dMgr The DiscoveryManagement instance * @param config Configuration object * * @throws Exception if the DynamicEventConsumer cannot be created */ public DynamicEventConsumer(final EventDescriptor edTemplate, final RemoteServiceEventListener listener, final MarshalledObject handback, final DiscoveryManagement dMgr, final Configuration config) throws Exception { super(edTemplate, listener, handback, config); ServiceTemplate template = new ServiceTemplate(null, null, new Entry[]{edTemplate}); Configuration configInstance = config==null?EmptyConfiguration.INSTANCE:config; sdm = new ServiceDiscoveryManager(dMgr, new LeaseRenewalManager(configInstance), configInstance); lCache = sdm.createLookupCache(template, null, null); lCache.addListener(new EventProducerManager()); } /** * Override parent's terminate() method to terminate the * ServiceDiscoveryManager */ public void terminate() { /* If this utility created a ServiceDiscoveryManager terminate it */ if(sdm!=null) { try { sdm.terminate(); } catch (IllegalStateException t) { logger.warn("Terminating SDM", t); } } super.terminate(); } /** * Override parent's register method to provide the ability if we've * discovered EventProducer instances that match we should register with * them */ public boolean register(final RemoteServiceEventListener listener, final MarshalledObject handback) { this.handback = handback; boolean added = super.register(listener, handback); try { if(lCache != null) { ServiceItem[] items = lCache.lookup(null, Integer.MAX_VALUE); for (ServiceItem item : items) { register(item); } } } catch(Exception e) { logger.error("Register RemoteServiceEventListener", e); } return (added); } /** * The EventProducerManager responds to serviceAdded transitions for * EventProducer instances which match the EventDescriptor */ class EventProducerManager extends ServiceDiscoveryAdapter { /** * An EventProducer has been added */ public void serviceAdded(final ServiceDiscoveryEvent sdEvent) { // sdEvent.getPreEventServiceItem() == null ServiceItem item = sdEvent.getPostEventServiceItem(); try { if(item != null && item.service != null) { if(logger.isTraceEnabled()) { String name = item.service.getClass().getName(); logger.trace("EventProducer discovered {}", name); } if(!eventSubscribers.isEmpty()) { register(item); ServiceFaultListener faultListener = new ServiceFaultListener(item.serviceID); lCache.addListener(faultListener); } } else { logger.warn("Unable to register EventProducer {}", item); } } catch(Exception e) { logger.error("Adding EventProducer", e); } } } /** * Manage service failure notifications */ class ServiceFaultListener extends ServiceDiscoveryAdapter { final ServiceID serviceID; ServiceFaultListener(final ServiceID serviceID) { this.serviceID = serviceID; } /** * An EventProducer has been removed */ public void serviceRemoved(final ServiceDiscoveryEvent sdEvent) { ServiceItem item = sdEvent.getPreEventServiceItem(); if(item.service != null) { if(item.serviceID.equals(serviceID)) { if(logger.isTraceEnabled()) { String name = item.service.getClass().getName(); logger.trace("EventProducer removed {}", name); } terminate(); } } else { logger.error("Unable to deregister EventProducer {}, unknown service", item); } } /** * Stop listening and remove from local tables */ void terminate() { lCache.removeListener(this); deregister(serviceID); } } }