/* * 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.io.Serializable; import java.text.MessageFormat; import java.util.logging.Level; import java.util.logging.Logger; import org.overlord.rtgov.ep.EventProcessor; import org.overlord.rtgov.ep.Predicate; import org.overlord.rtgov.ep.ResultHandler; /** * This class represents a node in the Event Processor Network. * */ public class Node { private static final Logger LOG=Logger.getLogger(Node.class.getName()); private String _name=null; private int _maxRetries=3; private long _retryInterval=0; private EventProcessor _eventProcessor=null; private Predicate _predicate=null; private java.util.List<String> _sourceNodes=new java.util.ArrayList<String>(); private java.util.List<String> _destinationSubjects=new java.util.ArrayList<String>(); private java.util.List<Notification> _notifications=new java.util.ArrayList<Notification>(); private java.util.List<Channel> _channels=new java.util.Vector<Channel>(); private ResultHandler _handler=null; private EPNContainer _container=null; /** * The default constructor for the event processor node. * */ public Node() { } /** * This method returns the node name. * * @return The name */ public String getName() { return (_name); } /** * This method sets the node name. * * @param name The name */ public void setName(String name) { _name = name; } /** * This method returns the maximum number of retries * for processing an event. * * @return The maximum number of events */ public int getMaxRetries() { return (_maxRetries); } /** * This method sets the maximum number of retries * for processing an event. * * @param max The maximum number of events */ public void setMaxRetries(int max) { _maxRetries = max; } /** * This method returns the retry interval. A * value of 0 means use the default for the * channel. * * @return The retry interval, or 0 to use the default for the channel */ public long getRetryInterval() { return (_retryInterval); } /** * This method sets the retry interval. A * value of 0 means use the default value for the * channel. * * @param interval The retry interval */ public void setRetryInterval(long interval) { _retryInterval = interval; } /** * This method returns the list of source nodes. * * @return The source nodes */ public java.util.List<String> getSourceNodes() { return (_sourceNodes); } /** * This method sets the list of sources. * * @param sources The source nodes */ public void setSourceNodes(java.util.List<String> sources) { _sourceNodes = sources; } /** * This method returns the list of destination subjects. * * @return The destination subjects */ public java.util.List<String> getDestinationSubjects() { return (_destinationSubjects); } /** * This method sets the list of destination subjects. * * @param destinations The destination subjects */ public void setDestinationSubjects(java.util.List<String> destinations) { _destinationSubjects = destinations; } /** * This method returns the event processor. * * @return The event processor */ public EventProcessor getEventProcessor() { return (_eventProcessor); } /** * This method sets the event processor. * * @param ep The event processor */ public void setEventProcessor(EventProcessor ep) { _eventProcessor = ep; } /** * This method returns the optional predicate that can be used * to filter the source events that should be processed. * * @return The optional predicate */ public Predicate getPredicate() { return (_predicate); } /** * This method sets the optional predicate that can be used * to filter the source events that should be processed. * * @param pred The optional predicate */ public void setPredicate(Predicate pred) { _predicate = pred; } /** * This method returns the list of notifications. * * @return The list of notifications */ public java.util.List<Notification> getNotifications() { return (_notifications); } /** * This method sets the list of notifications. * * @param notifications The list of notifications */ public void setNotifications(java.util.List<Notification> notifications) { _notifications = notifications; } /** * This method returns the list of channels associated with this * node. * * @return The channels */ protected java.util.List<Channel> getChannels() { return (_channels); } /** * This method initializes the node. * * @throws Exception Failed to initialize the node */ protected void init() throws Exception { if (getPredicate() != null) { getPredicate().init(); } if (getEventProcessor() == null) { throw new Exception("Event Processor has not been configured for node"); } getEventProcessor().init(); if (getEventProcessor().getAsynchronous()) { _handler = new NodeResultHandler(); getEventProcessor().setResultHandler(_handler); } } /** * This method sets the EPN container. * * @param container The container */ protected void setContainer(EPNContainer container) { _container = container; } /** * This method processes the supplied list of events against the * event processor configured with the node, to determine * which transformed events should be forwarded, and which need * to be returned to be retried. * * @param container The container * @param source The source node/subject that generated the event * @param events The list of events to be processed * @param retriesLeft The number of remaining retries * @return The events to retry, or null if no retries necessary * @throws Exception Failed to process events, and should result in transaction rollback * * @deprecated The container should be associated with the node using the 'setContainer' method */ protected EventList process(EPNContainer container, String source, EventList events, int retriesLeft) throws Exception { if (_container == null) { _container = container; } return (process(source, events, retriesLeft)); } /** * This method processes the supplied list of events against the * event processor configured with the node, to determine * which transformed events should be forwarded, and which need * to be returned to be retried. * * @param source The source node/subject that generated the event * @param events The list of events to be processed * @param retriesLeft The number of remaining retries * @return The events to retry, or null if no retries necessary * @throws Exception Failed to process events, and should result in transaction rollback */ @SuppressWarnings("unchecked") protected EventList process(String source, EventList events, int retriesLeft) throws Exception { java.util.List<Serializable> retries=null; java.util.List<Serializable> results=null; for (java.io.Serializable event : events) { if (getPredicate() == null || getPredicate().evaluate(event)) { try { java.io.Serializable processed=getEventProcessor().process(source, event, retriesLeft); if (LOG.isLoggable(Level.FINEST)) { LOG.log(Level.FINEST, "Processed event (retriesLeft="+retriesLeft+"): " +event+" processed="+processed); } if (processed != null) { if (results == null) { results = new java.util.ArrayList<Serializable>(); } if (processed instanceof java.util.Collection<?>) { results.addAll((java.util.Collection<? extends java.io.Serializable>)processed); } else { results.add(processed); } } } catch (Exception e) { if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Retry event (retriesLeft="+retriesLeft+"): "+event, e); } if (retries == null) { retries = new java.util.ArrayList<Serializable>(); if (retriesLeft == 0) { LOG.log(Level.WARNING, "No more retries left on node '" +getName()+"' (exception from first failed event)", e); } } retries.add(event); } } } if (results != null) { forward(new EventList(results)); } return (retries != null ? new EventList(retries) : null); } /** * This method forwards the results to any destinations that have been * defined. * * @param container The container * @param results The results * @throws Exception Failed to forward results * * @deprecated Use the alternative 'forward' method that does not require the container to be provided */ protected void forward(EPNContainer container, EventList results) throws Exception { if (_container == null) { _container = container; } forward(results); } /** * This method forwards the results to any destinations that have been * defined. * * @param results The results * @throws Exception Failed to forward results */ protected void forward(EventList results) throws Exception { if (_container != null) { _container.send(results, _channels); } else { throw new Exception("Cannot forward results as container has not been initialized"); } } /** * This method closes the node. * * @param container The container * @throws Exception Failed to close the node * * @deprecated Use the alternative 'close' method without the container parameter */ protected void close(EPNContainer container) throws Exception { close(); } /** * This method closes the node. * * @throws Exception Failed to close the node */ protected void close() throws Exception { for (Channel ch : _channels) { ch.close(); } _container = null; _handler = null; getEventProcessor().setResultHandler(null); getEventProcessor().close(); } /** * This class implements the result handler for this node. * * NOTE: This mechanism is experimental, so may change in the future. */ class NodeResultHandler implements ResultHandler { /** * {@inheritDoc} */ public void handle(java.io.Serializable result) { if (result != null) { java.util.List<java.io.Serializable> results=new java.util.ArrayList<java.io.Serializable>(); results.add(result); try { forward(_container, new EventList(results)); } catch (Exception e) { LOG.severe(MessageFormat.format(java.util.PropertyResourceBundle.getBundle( "epn-core.Messages").getString("EPN-CORE-19"), getName(), e.toString())); } } } } }