/** * Copyright (c) 2011-2014, OpenIoT * * This file is part of OpenIoT. * * OpenIoT is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, version 3 of the License. * * OpenIoT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with OpenIoT. If not, see <http://www.gnu.org/licenses/>. * * Contact: OpenIoT mailto: info@openiot.eu */ package org.openiot.ui.request.definition.web.model.validation.validators; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.Stack; import org.openiot.ui.request.commons.interfaces.GraphModel; import org.openiot.ui.request.commons.nodes.base.AbstractGraphNodeVisitor; import org.openiot.ui.request.commons.nodes.enums.EndpointType; import org.openiot.ui.request.commons.nodes.interfaces.GraphNode; import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeConnection; import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeEndpoint; import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeProperty; import org.openiot.ui.request.definition.web.model.validation.GraphValidationError; import org.openiot.ui.request.definition.web.model.validation.GraphValidationWarning; import org.openiot.ui.request.definition.web.model.validation.GraphValidationError.ErrorType; /** * * @author archie */ public class DefaultGraphNodeValidator extends AbstractGraphNodeVisitor { protected GraphModel model; protected List<GraphNode> visitedNodes; protected Stack<GraphNodeConnection> visitedConnectionGraphStack; protected List<GraphValidationWarning> validationWarnings; protected List<GraphValidationError> validationErrors; public DefaultGraphNodeValidator(GraphModel model) { this.model = model; this.visitedConnectionGraphStack = new Stack<GraphNodeConnection>(); this.visitedNodes = new ArrayList<GraphNode>(); this.validationErrors = new ArrayList<GraphValidationError>(); this.validationWarnings = new ArrayList<GraphValidationWarning>(); } public List<GraphValidationWarning> getValidationWarnings() { return validationWarnings; } public List<GraphValidationError> getValidationErrors() { return validationErrors; } public boolean validate() { validationErrors.clear(); validationWarnings.clear(); visitedConnectionGraphStack.clear(); visitedNodes.clear(); if( model.getNodes().isEmpty() ){ validationErrors.add(new GraphValidationError(ErrorType.EmptyGraph, "", "", "")); } // Visit all nodes once for (GraphNode node : model.getNodes()) { if (!visitedNodes.contains(node)) { visitViaReflection(node); } } return validationErrors.isEmpty(); } //------------------------------------------------------------------------- // Visitors //------------------------------------------------------------------------- @Override public void defaultVisit(GraphNode node) { // Check if we have visited this node before. // If so we need to check for closed loops if (visitedNodes.contains(node)) { boolean detectedCloseLoop = false; // Unwrap connection stack to detect origin point String elementIdList = ""; ListIterator<GraphNodeConnection> unwindIt = visitedConnectionGraphStack.listIterator(visitedConnectionGraphStack.size()); while (unwindIt.hasPrevious()) { GraphNodeConnection loopConnection = unwindIt.previous(); elementIdList += (elementIdList.isEmpty() ? "" : ", ") + loopConnection.getDestinationEndpoint().getUID(); elementIdList += (elementIdList.isEmpty() ? "" : ", ") + loopConnection.getSourceEndpoint().getUID(); // Reached this node if (loopConnection.getSourceNode().getUID().equals(node.getUID())) { detectedCloseLoop = true; break; } } if (detectedCloseLoop) { GraphValidationError error = new GraphValidationError(GraphValidationError.ErrorType.ConnectionsFormClosedLoop, node.getClass().getSimpleName(), "", elementIdList); validationErrors.add(error); } // We dont need to re-validate this node return; } // Add to visited set visitedNodes.add(node); // Validate node properties for (GraphNodeProperty property : node.getPropertyDefinitions()) { if (property.isRequired() && node.getPropertyValueMap().get(property.getName()) == null) { GraphValidationError error = new GraphValidationError(GraphValidationError.ErrorType.RequiredPropertyMissing, node.getClass().getSimpleName(), property.getName(), node.getUID()); validationErrors.add(error); } } // Validate endpoint connections boolean noConnections = true; for (GraphNodeEndpoint endpoint : node.getEndpointDefinitions()) { if (endpoint.getType().equals(EndpointType.Input)) { List<GraphNodeConnection> incomingConnections = model.findGraphEndpointConnections(endpoint); if (!incomingConnections.isEmpty()) { noConnections = false; } if (endpoint.isRequired() && incomingConnections.isEmpty()) { GraphValidationError error = new GraphValidationError(GraphValidationError.ErrorType.RequiredEndpointNotConnected, node.getClass().getSimpleName(), "", endpoint.getUID()); validationErrors.add(error); } } else { List<GraphNodeConnection> outgoingConnections = model.findGraphEndpointConnections(endpoint); if (!outgoingConnections.isEmpty()) { noConnections = false; } if (endpoint.isRequired() && outgoingConnections.isEmpty()) { GraphValidationError error = new GraphValidationError(GraphValidationError.ErrorType.RequiredEndpointNotConnected, node.getClass().getSimpleName(), "", endpoint.getUID()); validationErrors.add(error); } // Visit outgoing connection targets for (GraphNodeConnection outgoingConnection : outgoingConnections) { visitedConnectionGraphStack.push(outgoingConnection); visitViaReflection(outgoingConnection.getDestinationNode()); visitedConnectionGraphStack.pop(); } } } // Check for unconnected nodes if (noConnections) { GraphValidationWarning warning = new GraphValidationWarning(GraphValidationWarning.WarningType.NodeHasNoConnections, node.getClass().getSimpleName(), "", node.getUID()); validationWarnings.add(warning); } } }