/*
* 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.validation;
import java.text.MessageFormat;
import org.overlord.rtgov.epn.Network;
import org.overlord.rtgov.epn.Node;
import org.overlord.rtgov.epn.Notification;
import org.overlord.rtgov.epn.Subscription;
/**
* This class validates an Event Processor Network.
*
*/
public final class EPNValidator {
/**
* The default constructor.
*/
private EPNValidator() {
}
/**
* This method validates the supplied network and
* returns results via a supplied listener.
*
* @param epn The network to be validated
* @param l The listener
* @return Whether valid
*/
public static boolean validate(Network epn, EPNValidationListener l) {
boolean ret=true;
if (!validateNetwork(epn, l)) {
ret = false;
}
if (!validateSubscriptions(epn, l)) {
ret = false;
}
if (!validateNodes(epn, l)) {
ret = false;
}
return (ret);
}
/**
* This method validates the network.
*
* @param epn The network to be validated
* @param l The listener
* @return Whether valid
*/
protected static boolean validateNetwork(Network epn, EPNValidationListener l) {
boolean ret=true;
if (epn.getName() == null) {
l.error(epn, epn, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-6"),
"Network", "name"));
ret = false;
}
if (epn.getVersion() == null) {
l.error(epn, epn, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-6"),
"Network", "version"));
ret = false;
}
return (ret);
}
/**
* This method validates the network subscriptions.
*
* @param epn The network to be validated
* @param l The listener
* @return Whether valid
*/
protected static boolean validateSubscriptions(Network epn, EPNValidationListener l) {
boolean ret=true;
java.util.List<String> dups=new java.util.Vector<String>();
for (Subscription sub : epn.getSubscriptions()) {
if (sub.getSubject() == null) {
l.error(epn, sub, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-6"),
"Subscription", "nodeName"));
ret = false;
}
if (sub.getNodeName() == null) {
l.error(epn, sub, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-6"),
"Subscription", "subject"));
ret = false;
}
if (sub.getNodeName() != null && sub.getSubject() != null) {
// Check for duplicate subject/nodeName pair
String field=sub.getSubject()+":"+sub.getNodeName();
if (dups.contains(field)) {
// Report error
l.error(epn, sub, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-5"),
sub.getSubject(), sub.getNodeName()));
ret = false;
} else {
dups.add(field);
}
// Check if specified node name is in network
if (epn.getNode(sub.getNodeName()) == null) {
l.error(epn, sub, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-7"),
sub.getNodeName(), sub.getSubject()));
ret = false;
}
}
}
return (ret);
}
/**
* This method validates the network nodes.
*
* @param epn The network to be validated
* @param l The listener
* @return Whether valid
*/
protected static boolean validateNodes(Network epn, EPNValidationListener l) {
boolean ret=true;
for (Node node : epn.getNodes()) {
if (node.getName() == null) {
l.error(epn, node, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-6"),
"Node", "name"));
ret = false;
} else if (epn.getNode(node.getName()) != node) {
l.error(epn, node, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-8"),
node.getName()));
ret = false;
}
if (node.getEventProcessor() == null) {
l.error(epn, node, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-6"),
"Node", "eventProcessor"));
ret = false;
}
if (node.getName() != null) {
java.util.List<String> path=new java.util.Vector<String>();
path.add(node.getName());
for (String sourceNode : node.getSourceNodes()) {
// Check that source node exists in network
if (epn.getNode(sourceNode) == null) {
l.error(epn, node, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-9"),
sourceNode, node.getName()));
ret = false;
}
if (!checkCyclicDependency(epn, path, sourceNode, l)) {
ret = false;
}
}
}
// Validate the notifications
if (!validateNotifications(epn, node, l)) {
ret = false;
}
}
return (ret);
}
/**
* This method determines whether there is a cyclic dependency.
*
* @param epn The network
* @param path The path to the node
* @param node The source node being checked
* @param l The listener
* @return Whether valid
*/
protected static boolean checkCyclicDependency(Network epn, java.util.List<String> path,
String node, EPNValidationListener l) {
boolean ret=true;
if (node.equals(path.get(0))) {
// Cyclic dependency with the target node in the path
String pathString="";
for (String n : path) {
pathString += n+"->";
}
pathString += node;
l.error(epn, node, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-10"),
pathString));
ret = false;
// Don't process further, if have found cyclic dependency, although
// it does not involve the target node of interest
} else if (!path.contains(node)) {
Node sourceNode=epn.getNode(node);
if (sourceNode != null) {
path.add(node);
for (String sn : sourceNode.getSourceNodes()) {
if (!checkCyclicDependency(epn, path, sn, l)) {
ret = false;
}
}
path.remove(node);
}
}
return (ret);
}
/**
* This method validates the notifications associated with the supplied network
* and node.
*
* @param epn The network
* @param node The node
* @param l The listener
* @return Whether valid
*/
protected static boolean validateNotifications(Network epn, Node node, EPNValidationListener l) {
boolean ret=true;
for (Notification no : node.getNotifications()) {
if (no.getSubject() == null) {
l.error(epn, no, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-11"),
"Notification", "subject", node.getName()));
ret = false;
}
if (no.getType() == null) {
l.error(epn, no, MessageFormat.format(java.util.PropertyResourceBundle.getBundle(
"epn-core.Messages").getString("EPN-CORE-11"),
"Notification", "type", node.getName()));
ret = false;
}
}
return (ret);
}
}