/*
* 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()));
}
}
}
}
}