/* * 2012-3 Red Hat Inc. and/or its affiliates and other contributors. * * 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.overlord.rtgov.epn; import java.text.MessageFormat; import java.util.logging.Level; import java.util.logging.Logger; import org.overlord.rtgov.common.util.VersionUtil; import org.overlord.rtgov.epn.validation.EPNValidationListener; import org.overlord.rtgov.epn.validation.EPNValidator; import org.overlord.rtgov.internal.epn.jmx.EPNManagement; /** * This class represents the abstract Event Process Network Manager * used as the base for any concrete implementation. * */ public abstract class AbstractEPNManager implements EPNManager { private static final Logger LOG=Logger.getLogger(AbstractEPNManager.class.getName()); private java.util.Map<String, NetworkList> _networkMap=new java.util.HashMap<String, NetworkList>(); private java.util.Map<String, java.util.List<Network>> _subjectMap= new java.util.HashMap<String, java.util.List<Network>>(); private java.util.Map<String, java.util.List<NotificationListener>> _notificationListeners= new java.util.HashMap<String, java.util.List<NotificationListener>>(); private java.util.List<NetworkListener> _networkListeners= new java.util.ArrayList<NetworkListener>(); private boolean _usePrePostEventListProcessing=false; private EPNManagement _epnManagement=null; /** * This is the default constructor. */ public AbstractEPNManager() { } /** * Initialize the EPNManager. */ public void init() { // Check if managed if (isManaged() && _epnManagement == null) { _epnManagement = new EPNManagement(this); _epnManagement.init(); } } /** * This method returns the Event Processor Network Container. * * @return The container */ protected abstract EPNContainer getContainer(); /** * This method determines whether the EPNManager is managed. If managed, * then its MBean will be registered with the MBeanServer and available * to JMX compliant management systems. * * @return Whether the EPNManager is managed */ protected boolean isManaged() { return (false); } /** * {@inheritDoc} */ public void register(Network network) throws Exception { LOG.info(MessageFormat.format(java.util.PropertyResourceBundle.getBundle( "epn-core.Messages").getString("EPN-CORE-13"), network.getName(), network.getVersion())); network.init(getContainer()); // Validate network if (!EPNValidator.validate(network, getValidationListener())) { // Close the network network.close(); throw new Exception(MessageFormat.format(java.util.PropertyResourceBundle.getBundle( "epn-core.Messages").getString("EPN-CORE-12"), network.getName(), network.getVersion())); } synchronized (_networkMap) { NetworkList nl=_networkMap.get(network.getName()); if (nl == null) { nl = new NetworkList(); _networkMap.put(network.getName(), nl); } Network oldnet=nl.getCurrent(); // Add registered network to the list nl.add(network); // Check if current instance has changed to the // newly registered network if (nl.getCurrent() == network) { currentNetworkChanged(oldnet, network); } } synchronized (_networkListeners) { for (int i=0; i < _networkListeners.size(); i++) { _networkListeners.get(i).registered(network); } } } /** * This method returns the validation listener. * * @return The validation listener */ protected EPNValidationListener getValidationListener() { return (new EPNValidationListener() { public void error(Network epn, Object target, String issue) { LOG.severe(issue); } }); } /** * {@inheritDoc} */ public void unregister(String networkName, String version) throws Exception { LOG.info(MessageFormat.format(java.util.PropertyResourceBundle.getBundle( "epn-core.Messages").getString("EPN-CORE-14"), networkName, version)); Network network=null; synchronized (_networkMap) { NetworkList nl=_networkMap.get(networkName); if (nl != null) { network = (version == null ? nl.getCurrent() : nl.getVersion(version)); if (network != null) { Network oldcur=nl.getCurrent(); nl.remove(network); Network newcur=nl.getCurrent(); if (newcur != oldcur) { currentNetworkChanged(oldcur, newcur); } } if (nl.size() == 0) { _networkMap.remove(networkName); } } } if (network != null) { synchronized (_networkListeners) { for (int i=0; i < _networkListeners.size(); i++) { _networkListeners.get(i).unregistered(network); } } network.close(); } } /** * This method is called to handle a change in the current version * of a network, due to a new (more recent) version being registered * or a current version being unregistered. * * @param oldNet The old network version * @param newNet The new network version */ protected void currentNetworkChanged(Network oldNet, Network newNet) { if (oldNet != null) { unregisterSubjects(oldNet); } if (newNet != null) { registerSubjects(newNet); } } /** * This method registers the supplied network against the * subjects it is interested in. * * @param network The network */ protected void registerSubjects(Network network) { for (String subject : network.subjects()) { java.util.List<Network> networks=_subjectMap.get(subject); if (networks == null) { networks = new java.util.concurrent.CopyOnWriteArrayList<Network>(); _subjectMap.put(subject, networks); } networks.add(network); } } /** * This method unregisters the supplied network from the * subjects it is interested in. * * @param network The network */ protected void unregisterSubjects(Network network) { for (String subject : network.subjects()) { java.util.List<Network> networks=_subjectMap.get(subject); if (networks != null) { networks.remove(network); if (networks.size() == 0) { _subjectMap.remove(subject); } } } } /** * {@inheritDoc} */ public void addNotificationListener(String subject, NotificationListener l) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Register notification listener="+l+" on subject="+subject); } synchronized (_notificationListeners) { java.util.List<NotificationListener> listeners=_notificationListeners.get(subject); if (listeners == null) { listeners = new java.util.ArrayList<NotificationListener>(); _notificationListeners.put(subject, listeners); } listeners.add(l); } } /** * {@inheritDoc} */ public void removeNotificationListener(String subject, NotificationListener l) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Unregister notification listener="+l+" on subject="+subject); } synchronized (_notificationListeners) { java.util.List<NotificationListener> listeners=_notificationListeners.get(subject); if (listeners != null) { listeners.remove(l); if (listeners.size() == 0) { _notificationListeners.remove(subject); } } } } /** * {@inheritDoc} */ public void addNetworkListener(NetworkListener l) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Register network listener="+l); } synchronized (_networkListeners) { _networkListeners.add(l); } } /** * {@inheritDoc} */ public void removeNetworkListener(NetworkListener l) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Unregister network listener="+l); } synchronized (_networkListeners) { _networkListeners.remove(l); } } /** * This method sets the last accessed timestamp on the supplied * network. * * @param network The network * @param timestamp The timestamp */ protected void setLastAccessed(Network network, long timestamp) { network.lastAccessed(timestamp); } /** * This method returns the network associated with the * supplied name. * * @param name The network name * @param version The version, or null for current version * @return The network, or null if not found */ protected Network getNetwork(String name, String version) { Network ret=null; NetworkList nl=_networkMap.get(name); if (nl != null) { ret = (version == null ? nl.getCurrent() : nl.getVersion(version)); } return (ret); } /** * This method returns the list of networks that subscribe to * the supplied subject. * * @param subject The subject * @return The list of networks, or null of no networks subscribe to the subject */ protected java.util.List<Network> getNetworksForSubject(String subject) { return (_subjectMap.get(subject)); } /** * This method returns the node associated with the * supplied network and node name. * * @param networkName The network name * @param version The version, or null for current * @param nodeName The node name * @return The node, or null if not found * @throws Exception Failed to find the specified node */ protected Node getNode(String networkName, String version, String nodeName) throws Exception { Network net=getNetwork(networkName, version); if (net == null) { throw new Exception("No network '"+networkName+"' version["+version+"] was found"); } Node node=net.getNode(nodeName); if (node == null) { throw new Exception("No node '"+nodeName+"' was found in network '"+networkName +"' version["+version+""); } return (node); } /** * This method sets whether to use pre/post event list processing. * * @param b Whether to use pre/post event list processing */ protected void setUsePrePostEventListProcessing(boolean b) { _usePrePostEventListProcessing = b; } /** * This method deserializes the events in the context of the supplied * network. This method is only relevant for EPN manager implementations * that load EPN networks in their own classloader context. * * @param events The events * @param network The network */ protected void preProcessEvents(EventList events, Network network) { preProcessEvents(events, network.contextClassLoader()); } /** * This method deserializes the events in the context of the supplied * classloader. This method is only relevant for EPN manager implementations * that load EPN networks in their own classloader context. * * @param events The events * @param classloader The classloader */ protected void preProcessEvents(EventList events, ClassLoader classloader) { if (classloader != null) { events.resolve(classloader); } } /** * This method resets the events, to enable them to be used in the * context of another classloader. This method is only relevant for EPN * manager implementations that load EPN networks in their own * classloader context. * * @param events The events */ protected void postProcessEvents(EventList events) { events.reset(); } /** * This method dispatches a set of events directly to the supplied * node. * * @param network The network * @param node The node * @param source The source node/subject * @param events The list of events to be processed * @param retriesLeft The number of retries left * @return The events to retry, or null if no retries necessary * @throws Exception Failed to dispatch the events for processing */ protected EventList process(Network network, Node node, String source, EventList events, int retriesLeft) throws Exception { if (LOG.isLoggable(Level.FINEST)) { LOG.finest("Process events on network="+network.getName()+" node="+node.getName() +" source="+source+" retriesLeft="+retriesLeft+" events="+events); } EventList ret=node.process(source, events, retriesLeft); if (ret == null || ret.size() < events.size()) { EventList notifyList=null; for (int i=0; i < node.getNotifications().size(); i++) { Notification no=node.getNotifications().get(i); if (no.getType() == NotificationType.Processed) { if (notifyList == null) { if (ret != null) { java.util.List<java.io.Serializable> processed = new java.util.ArrayList<java.io.Serializable>(); for (int j=0; j < events.size(); j++) { java.io.Serializable event=events.get(j); if (!ret.contains(event)) { processed.add(event); } } if (processed.size() > 0) { notifyList = new EventList(processed); } } else { notifyList = events; } } if (notifyList != null) { notifyListeners(no.getSubject(), notifyList); } } } } if (ret != null) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Processed events on network="+network.getName() +" version="+network.getVersion()+" node="+node.getName() +" source="+source+" retrying="+ret); } } else if (LOG.isLoggable(Level.FINEST)) { LOG.finest("Processed events on network="+network.getName() +" version="+network.getVersion()+" node="+node.getName() +" source="+source+": no retries"); } return (ret); } /** * This method sends a notification to any registered listeners that * a situation has occurred associated with the specified subject. * * @param subject The subject * @param events The list of events * @throws Exception Failed to notify */ protected void notifyListeners(String subject, EventList events) throws Exception { dispatchNotificationToListeners(subject, events); } /** * This method dispatches the notifications to the registered listeners. * * @param subject The subject * @param events The list of events */ protected void dispatchNotificationToListeners(String subject, EventList events) { if (LOG.isLoggable(Level.FINEST)) { LOG.finest("Notify processed events on subject="+subject +" events="+events); } java.util.List<NotificationListener> listeners=_notificationListeners.get(subject); if (listeners != null) { for (int i=0; i < listeners.size(); i++) { NotificationListener nl=listeners.get(i); if (_usePrePostEventListProcessing && !(nl instanceof ContextualNotificationListener)) { try { preProcessEvents(events, nl.getClass().getClassLoader()); } catch (Throwable t) { LOG.log(Level.SEVERE, MessageFormat.format(java.util.PropertyResourceBundle.getBundle( "epn-core.Messages").getString("EPN-CORE-1"), nl.getClass().getName()), t); // Don't attempt to send events to the node listener continue; } } nl.notify(subject, events); if (_usePrePostEventListProcessing) { postProcessEvents(events); } } } } /** * {@inheritDoc} */ public void close() throws Exception { if (_epnManagement != null) { _epnManagement.close(); _epnManagement = null; } } /** * This class represents a list of Network instances * for the same name, but different versions. * */ public class NetworkList { private java.util.List<Network> _networks=new java.util.ArrayList<Network>(); /** * The constructor. */ public NetworkList() { } /** * This method adds a new instance of the Network to the list. * * @param network The network */ public void add(Network network) { synchronized (_networks) { boolean inserted=false; for (int i=0; i < _networks.size(); i++) { if (VersionUtil.isNewerVersion(_networks.get(i).getVersion(), network.getVersion())) { _networks.add(i, network); inserted = true; break; } } if (!inserted) { _networks.add(network); } } } /** * This method removes an instance of the Network from the list. * * @param network The network */ public void remove(Network network) { synchronized (_networks) { _networks.remove(network); } } /** * This method returns the most recent instance of the network. * * @return The current instance of the network */ public Network getCurrent() { Network ret=null; synchronized (_networks) { if (_networks.size() > 0) { ret = _networks.get(0); } } return (ret); } /** * This method returns the network instance associated with * the supplied version. * * @param version The version * @return The network instance, or null if not found */ public Network getVersion(String version) { Network ret=null; synchronized (_networks) { for (Network network : _networks) { if (network.getVersion().equals(version)) { ret = network; break; } } } return (ret); } /** * This method returns the list of networks. * * @return The list of networks */ public java.util.List<Network> getNetworks() { return (_networks); } /** * This method returns the number of networks in the list. * * @return The number of networks */ public int size() { synchronized (_networks) { return (_networks.size()); } } } }