/* * 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.service; import com.sun.jini.config.Config; import net.jini.config.Configuration; import net.jini.core.event.EventRegistration; import net.jini.core.event.RemoteEventListener; import net.jini.core.event.UnknownEventException; import net.jini.core.lease.LeaseDeniedException; import net.jini.id.Uuid; import net.jini.security.BasicProxyPreparer; import net.jini.security.ProxyPreparer; import org.rioproject.event.EventDescriptor; import org.rioproject.event.EventHandler; import org.rioproject.event.EventProducer; import org.rioproject.impl.watch.WatchRegistry; import org.rioproject.servicecore.Service; import org.rioproject.watch.WatchDataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.rmi.MarshalledObject; import java.rmi.RemoteException; import java.util.Map; /** * The ServiceProvider is an abstract class that provides the infrastructure * required to make a Jini service. This class needs to be extended by Service * developers. All ServiceProvider instances can be an Event Producer. An Event * Producer is a service that has a zero-to-many dependency between objects such * that when it's state changes all it's dependants are notified. All * ServiceProvider instances provide support for the Rio Watchable framework. * The Rio Watchable framework provides a mechanism to collect and analyze * programmer-defined metrics defined in local and distributed applications * <p> * The ServiceProvider supports the following configuration entries; where each * configuration entry name is associated with the component name <span *="" * style="font-family: monospace;">org.rioproject.resources.servicecore </span> * <br> *   <br> * </p> * <ul> * <li><span style="font-weight: bold;">eventListenerPreparer </span> <table * cellpadding="2" *="" cellspacing="2" border="0" style="text-align: left; * width: 100%;"> <tbody> * <tr> * <td style="vertical-align: top; text-align: right;">Type:</td> * <td style="vertical-align: top;">ProxyPreparer</td> * </tr> * <tr> * <td style="vertical-align: top; text-align: right;">Default:</td> * <td style="vertical-align: top;">new BasicProxyPreparer() <code></code> * <br> * </td> * </tr> * <tr> * <td style="vertical-align: top; text-align: right;">Description:</td> * <td style="vertical-align: top;">Specifies the proxy preparer to use for * <code>RemoteEventListener</code> s registered with this service in calls to * <code>ServiceProvider.register(org.rioproject.event.EventDescriptor,  net.jini.core.event.RemoteEventListener, java.rmi.MarshalledObject, long)</code>. * During event notification, this service calls the <code>notify</code> * method on <code>RemoteEventListener</code> instances returned from this * preparer. This entry is obtained at service start and restart.</td> * </tr> * </tbody> </table></li> * </ul> * * @author Dennis Reedy */ public abstract class ServiceProvider implements Service { /** * The eventTable associates an EventHandler to an EventDescriptor for the * ServiceProvider. Event registration requests for events this * ServiceProvider has advertised will consult the eventTable to determine * the correct EventHandler to use in order to return an event registration */ protected Map<Long, EventHandler> eventTable; /** * The watchRegistry is used to fetch WatchDataSource instances that have * been created and registered in this ServiceProvider */ protected WatchRegistry watchRegistry; /** The Configuration for the ServiceProvider */ private Configuration config; /** Preparer for received remote event listeners */ private ProxyPreparer listenerPreparer = new BasicProxyPreparer(); /** Name for use accessing Configuration elements and getting a Logger */ private static final String COMPONENT = "org.rioproject.resources.servicecore"; /** A Logger */ static final Logger logger = LoggerFactory.getLogger(COMPONENT); /** * Set the Configuration for the ServiceProvider * * @param config The Configuration */ public void setConfiguration(Configuration config) { this.config = config; if(config != null) { try { listenerPreparer =(ProxyPreparer)Config.getNonNullEntry(config, COMPONENT, "eventListenerPreparer", ProxyPreparer.class, listenerPreparer); } catch(Exception e) { logger.warn("Getting eventListenerPreparer", e); } } } /** * Get the Configuration for the ServiceProvider * * @return The Configuration */ public Configuration getConfiguration() { return (config); } /** * @see org.rioproject.event.EventProducer#register */ public EventRegistration register(EventDescriptor descriptor, RemoteEventListener listener, MarshalledObject handback, long duration) throws LeaseDeniedException, UnknownEventException, RemoteException { if(descriptor == null) throw new IllegalArgumentException("descriptor is null"); if(descriptor.eventID == null) throw new UnknownEventException("Event ID is null"); EventHandler eHandler = eventTable.get(descriptor.eventID); if(eHandler == null) throw new UnknownEventException("Unknown event ID "+descriptor.eventID); /* Prepare the RemoteEventListener */ RemoteEventListener preparedListener = (RemoteEventListener)listenerPreparer.prepareProxy(listener); if(logger.isDebugEnabled()) logger.debug("Register listener {} for Event {}", preparedListener.toString(), descriptor.toString()); Object o = getServiceProxy(); if(!(o instanceof EventProducer)) { String reason = "Proxy returned from getServiceProxy() does " + "not implement "+EventProducer.class.getName(); logger.warn(reason); throw new ClassCastException(reason); } return (eHandler.register(o, preparedListener, handback, duration)); } /** * Left for concrete implementations of this class to implement */ public abstract Object getAdmin(); /** * Left for concrete implementations of this class to implement */ public abstract void destroy(); /** * Concrete implementations must define a mechanism to retrieve the proxy to * represent the service on the network * * @return A proxy suitable for communication to the service */ public abstract Object getServiceProxy(); /** * Return the Uuid for the Service * * @return The Uuid */ public abstract Uuid getUuid(); /** * @see org.rioproject.watch.Watchable#fetch() */ public WatchDataSource[] fetch() { WatchDataSource[] wds = new WatchDataSource[0]; if(watchRegistry != null) { wds = watchRegistry.fetch(); } else { logger.warn("WatchRegistry is null"); } return(wds); } /** @see org.rioproject.watch.Watchable#fetch(String) */ public WatchDataSource fetch(String id) { WatchDataSource wds = null; if(watchRegistry!=null) { wds = watchRegistry.fetch(id); } else { logger.warn("WatchRegistry is null"); } return(wds); } /** * Set the event table. * * @param eventTable The event table */ public void setEventTable(Map<Long, EventHandler> eventTable) { this.eventTable = eventTable; } /** * Get the event table. * * @return The event table */ public Map<Long, EventHandler> getEventTable() { return eventTable; } /** * Get the WatchDataSourceRegistry * * @return The WatchRegistry */ public WatchRegistry getWatchRegistry() { return (watchRegistry); } /** * Set the WatchDataSourceRegistry * * @param watchRegistry The WatchRegistry */ public void setWatchRegistry(WatchRegistry watchRegistry) { this.watchRegistry = watchRegistry; } }