From: Tony Tkacik Date: Fri, 28 Feb 2014 14:03:52 +0000 (+0000) Subject: Merge "Cleanup dependencyManagement overrides" X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~364 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=fc41508e7c5018eb8eefad4a48e00719cba8d9ed;hp=dba0c9b989781d831fc67e6a9e749aa36f48479b Merge "Cleanup dependencyManagement overrides" --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index d42f1fd83d..c0e857c79c 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -1765,6 +1765,7 @@ maven-surefire-plugin ${surefire.version} + ${testvm.argLine} logback.configurationFile diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/02-toaster-sample.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/02-toaster-sample.xml new file mode 100644 index 0000000000..c481485c92 --- /dev/null +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/02-toaster-sample.xml @@ -0,0 +1,73 @@ + + + + + + + prefix:toaster-provider-impl + + toaster-provider-impl + + + binding:binding-rpc-registry + binding-rpc-broker + + + + + binding:binding-notification-service + + binding-notification-broker + + + + + + prefix:toaster-consumer-impl + + toaster-consumer-impl + + + binding:binding-rpc-registry + binding-rpc-broker + + + + + binding:binding-notification-service + + binding-notification-broker + + + + + + + toaster:toaster-provider + + toaster-provider + /modules/module[type='toaster-provider-impl'][name='toaster-provider-impl'] + + + + toaster:toaster-consumer + + toaster-consumer + /modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl'] + + + + + + + + + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31 + + + + diff --git a/opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java b/opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java index c56eb60a6b..3ad08ca207 100644 --- a/opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java +++ b/opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java @@ -8,6 +8,19 @@ package org.opendaylight.controller.forwardingrulesmanager; +import java.io.Serializable; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + import org.opendaylight.controller.configuration.ConfigurationObject; import org.opendaylight.controller.sal.action.Action; import org.opendaylight.controller.sal.action.ActionType; @@ -30,38 +43,19 @@ import org.opendaylight.controller.sal.action.SetTpSrc; import org.opendaylight.controller.sal.action.SetVlanId; import org.opendaylight.controller.sal.action.SetVlanPcp; import org.opendaylight.controller.sal.action.SwPath; -import org.opendaylight.controller.sal.core.ContainerFlow; -import org.opendaylight.controller.sal.core.IContainer; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; -import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.HexEncode; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NetUtils; -import org.opendaylight.controller.sal.utils.NodeConnectorCreator; -import org.opendaylight.controller.sal.utils.ServiceHelper; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; -import org.opendaylight.controller.switchmanager.ISwitchManager; -import org.opendaylight.controller.switchmanager.Switch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.io.Serializable; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Configuration Java Object which represents a flow configuration information * for Forwarding Rules Manager. @@ -608,15 +602,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable { return true; } - public boolean isPortValid(Switch sw, String port) { - if (sw == null) { - log.debug("switch info is not available. Skip checking if port is part of a switch or not."); - return true; - } - NodeConnector nc = NodeConnectorCreator.createNodeConnector(port, sw.getNode()); - return sw.getNodeConnectors().contains(nc); - } - public boolean isVlanIdValid(String vlanId) { int vlan = Integer.decode(vlanId); return ((vlan >= 0) && (vlan < 4096)); @@ -647,45 +632,11 @@ public class FlowConfig extends ConfigurationObject implements Serializable { return (proto != null); } - private Status conflictWithContainerFlow(IContainer container) { - // Return true if it's default container - if (container.getName().equals(GlobalConstants.DEFAULT.toString())) { - return new Status(StatusCode.SUCCESS); - } - - // No container flow = no conflict - List cFlowList = container.getContainerFlows(); - if (((cFlowList == null)) || cFlowList.isEmpty()) { - return new Status(StatusCode.SUCCESS); - } - - // Check against each container's flow - Flow flow = this.getFlow(); - - // Configuration is rejected if it conflicts with _all_ the container - // flows - for (ContainerFlow cFlow : cFlowList) { - if (cFlow.allowsFlow(flow)) { - log.trace("Config is congruent with at least one container flow"); - return new Status(StatusCode.SUCCESS); - } - } - String msg = "Flow Config conflicts with all existing container flows"; - log.trace(msg); - - return new Status(StatusCode.BADREQUEST, msg); - } - - public Status validate(IContainer container) { + public Status validate() { EtherIPType etype = EtherIPType.ANY; EtherIPType ipsrctype = EtherIPType.ANY; EtherIPType ipdsttype = EtherIPType.ANY; - String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container.getName(); - ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, - this); - - Switch sw = null; try { // Flow name cannot be internal flow signature if (!isValidResourceName(name) || isInternalFlow()) { @@ -696,20 +647,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable { return new Status(StatusCode.BADREQUEST, "Node is null"); } - if (switchManager != null) { - for (Switch device : switchManager.getNetworkDevices()) { - if (device.getNode().equals(node)) { - sw = device; - break; - } - } - if (sw == null) { - return new Status(StatusCode.BADREQUEST, String.format("Node %s not found", node)); - } - } else { - log.debug("switchmanager is not set yet"); - } - if (priority != null) { if (Integer.decode(priority) < 0 || (Integer.decode(priority) > 65535)) { return new Status(StatusCode.BADREQUEST, String.format("priority %s is not in the range 0 - 65535", @@ -722,14 +659,8 @@ public class FlowConfig extends ConfigurationObject implements Serializable { Long.decode(cookie); } - if (ingressPort != null) { - if (!isPortValid(sw, ingressPort)) { - String msg = String.format("Ingress port %s is not valid for the Switch", ingressPort); - if (!containerName.equals(GlobalConstants.DEFAULT.toString())) { - msg += " in Container " + containerName; - } - return new Status(StatusCode.BADREQUEST, msg); - } + if (ingressPort != null && ingressPort.isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Invalid ingress port"); } if ((vlanId != null) && !isVlanIdValid(vlanId)) { @@ -832,48 +763,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable { return new Status(StatusCode.BADREQUEST, "Actions value is null or empty"); } for (String actiongrp : actions) { - // check output ports - sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp); - if (sstr.matches()) { - for (String t : sstr.group(1).split(",")) { - if (t != null) { - if (!isPortValid(sw, t)) { - String msg = String.format("Output port %s is not valid for this switch", t); - if (!containerName.equals(GlobalConstants.DEFAULT.toString())) { - msg += " in Container " + containerName; - } - return new Status(StatusCode.BADREQUEST, msg); - } - } - } - continue; - } - // check enqueue - sstr = Pattern.compile("ENQUEUE=(.*)").matcher(actiongrp); - if (sstr.matches()) { - for (String t : sstr.group(1).split(",")) { - if (t != null) { - String port = t.split(":")[0]; - if (!isPortValid(sw, port)) { - String msg = String.format("Output port %d is not valid for this switch", port); - if (!containerName.equals(GlobalConstants.DEFAULT.toString())) { - msg += " in Container " + containerName; - } - return new Status(StatusCode.BADREQUEST, msg); - } - } - } - continue; - } - // Check src IP - sstr = Pattern.compile(ActionType.FLOOD.toString()).matcher(actiongrp); - if (sstr.matches()) { - if (!containerName.equals(GlobalConstants.DEFAULT.toString())) { - return new Status(StatusCode.BADREQUEST, String.format( - "flood is not allowed in container %s", containerName)); - } - continue; - } // Check src IP sstr = Pattern.compile(ActionType.SET_NW_SRC.toString() + "=(.*)").matcher(actiongrp); if (sstr.matches()) { @@ -965,11 +854,6 @@ public class FlowConfig extends ConfigurationObject implements Serializable { continue; } } - // Check against the container flow - Status status; - if (!containerName.equals(GlobalConstants.DEFAULT.toString()) && !(status = conflictWithContainerFlow(container)).isSuccess()) { - return status; - } } catch (NumberFormatException e) { return new Status(StatusCode.BADREQUEST, String.format("Invalid number format %s", e.getMessage())); } diff --git a/opendaylight/forwardingrulesmanager/api/src/test/java/org/opendaylight/controller/forwardingrulesmanager/frmTest.java b/opendaylight/forwardingrulesmanager/api/src/test/java/org/opendaylight/controller/forwardingrulesmanager/frmTest.java index 48e1f07716..685ccdb7c4 100644 --- a/opendaylight/forwardingrulesmanager/api/src/test/java/org/opendaylight/controller/forwardingrulesmanager/frmTest.java +++ b/opendaylight/forwardingrulesmanager/api/src/test/java/org/opendaylight/controller/forwardingrulesmanager/frmTest.java @@ -257,7 +257,7 @@ public class frmTest { FlowConfig flowConfig = new FlowConfig(); Assert.assertFalse(flowConfig.isInternalFlow()); flowConfig.setName("__Internal__"); - Status status = flowConfig.validate(null); + Status status = flowConfig.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("name")); Assert.assertTrue(flowConfig.isInternalFlow()); @@ -509,228 +509,228 @@ public class frmTest { @Test public void testValid() throws UnknownHostException { FlowConfig fc2 = createSampleFlowConfig(); - Assert.assertTrue(fc2.validate(null).isSuccess()); + Assert.assertTrue(fc2.validate().isSuccess()); FlowConfig fc = new FlowConfig(); - Status status = fc.validate(null); + Status status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Invalid name")); fc.setName("Config"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Node is null")); fc.setNode(Node.fromString(Node.NodeIDType.OPENFLOW, "1")); - Assert.assertFalse(fc.validate(null).isSuccess()); + Assert.assertFalse(fc.validate().isSuccess()); List actions = new ArrayList(); fc.setActions(actions); - Assert.assertFalse(fc.validate(null).isSuccess()); + Assert.assertFalse(fc.validate().isSuccess()); actions.add("OUTPUT=2"); fc.setActions(actions); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setPriority("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 65535")); fc.setPriority("100000"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 65535")); fc.setPriority("2000"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setCookie("100"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setIngressPort("100"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setVlanId(("-1")); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 4095")); fc.setVlanId("5000"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 4095")); fc.setVlanId("100"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setVlanPriority("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 7")); fc.setVlanPriority("9"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("is not in the range 0 - 7")); fc.setVlanPriority("5"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setEtherType("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Ethernet type")); fc.setEtherType("0xfffff"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Ethernet type")); fc.setEtherType("0x800"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setTosBits("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("IP ToS bits")); fc.setTosBits("65"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("IP ToS bits")); fc.setTosBits("60"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setSrcPort("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Transport source port")); fc.setSrcPort("0xfffff"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Transport source port")); fc.setSrcPort("0"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setSrcPort("0x00ff"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setSrcPort("0xffff"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setDstPort("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Transport destination port")); fc.setDstPort("0xfffff"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Transport destination port")); fc.setDstPort("0"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setDstPort("0x00ff"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setDstPort("0xffff"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setSrcMac("abc"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Ethernet source address")); fc.setSrcMac("00:A0:C9:14:C8:29"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setDstMac("abc"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Ethernet destination address")); fc.setDstMac("00:A0:C9:22:AB:11"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setSrcIp("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("IP source address")); fc.setSrcIp("2001:420:281:1004:407a:57f4:4d15:c355"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Src IP")); fc.setEtherType("0x86dd"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setSrcIp("1.1.1.1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Src IP")); fc.setEtherType("0x800"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setDstIp("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("IP destination address")); fc.setDstIp("2001:420:281:1004:407a:57f4:4d15:c355"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Dst IP")); fc.setEtherType("0x86dd"); fc.setSrcIp("2001:420:281:1004:407a:57f4:4d15:c355"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setDstIp("2.2.2.2"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Type mismatch between Ethernet & Dst IP")); fc.setEtherType("0x800"); fc.setSrcIp("1.1.1.1"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setEtherType(null); fc.setSrcIp("2001:420:281:1004:407a:57f4:4d15:c355"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("IP Src Dest Type mismatch")); fc.setSrcIp("1.1.1.1"); fc.setIdleTimeout("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Idle Timeout value")); fc.setIdleTimeout("0xfffff"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Idle Timeout value")); fc.setIdleTimeout("10"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); fc.setHardTimeout("-1"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Hard Timeout value")); fc.setHardTimeout("0xfffff"); - status = fc.validate(null); + status = fc.validate(); Assert.assertFalse(status.isSuccess()); Assert.assertTrue(status.getDescription().contains("Hard Timeout value")); fc.setHardTimeout("10"); - Assert.assertTrue(fc.validate(null).isSuccess()); + Assert.assertTrue(fc.validate().isSuccess()); } diff --git a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java index b94103fb1c..614c39e060 100644 --- a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java +++ b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java @@ -50,6 +50,9 @@ import org.opendaylight.controller.forwardingrulesmanager.PortGroupProvider; import org.opendaylight.controller.forwardingrulesmanager.implementation.data.FlowEntryDistributionOrder; import org.opendaylight.controller.sal.action.Action; import org.opendaylight.controller.sal.action.ActionType; +import org.opendaylight.controller.sal.action.Enqueue; +import org.opendaylight.controller.sal.action.Flood; +import org.opendaylight.controller.sal.action.FloodAll; import org.opendaylight.controller.sal.action.Output; import org.opendaylight.controller.sal.connection.ConnectionLocality; import org.opendaylight.controller.sal.core.Config; @@ -243,6 +246,57 @@ public class ForwardingRulesManager implements return null; } + /** + * Checks if the FlowEntry targets are valid for this container + * + * @param flowEntry + * The flow entry to test + * @return a Status object representing the result of the validation + */ + private Status validateEntry(FlowEntry flowEntry) { + // Node presence check + Node node = flowEntry.getNode(); + if (!switchManager.getNodes().contains(node)) { + return new Status(StatusCode.BADREQUEST, String.format("Node %s is not present in this container", node)); + } + + // Ports and actions validation check + Flow flow = flowEntry.getFlow(); + Match match = flow.getMatch(); + if (match.isPresent(MatchType.IN_PORT)) { + NodeConnector inputPort = (NodeConnector)match.getField(MatchType.IN_PORT).getValue(); + if (!switchManager.getNodeConnectors(node).contains(inputPort)) { + String msg = String.format("Ingress port %s is not present on this container", inputPort); + return new Status(StatusCode.BADREQUEST, msg); + } + } + for (Action action : flow.getActions()) { + if (action instanceof Flood && !GlobalConstants.DEFAULT.toString().equals(getContainerName())) { + return new Status(StatusCode.BADREQUEST, String.format("Flood is only allowed in default container")); + } + if (action instanceof FloodAll && !GlobalConstants.DEFAULT.toString().equals(getContainerName())) { + return new Status(StatusCode.BADREQUEST, String.format("FloodAll is only allowed in default container")); + } + if (action instanceof Output) { + Output out = (Output)action; + NodeConnector outputPort = out.getPort(); + if (!switchManager.getNodeConnectors(node).contains(outputPort)) { + String msg = String.format("Output port %s is not present on this container", outputPort); + return new Status(StatusCode.BADREQUEST, msg); + } + } + if (action instanceof Enqueue) { + Enqueue out = (Enqueue)action; + NodeConnector outputPort = out.getPort(); + if (!switchManager.getNodeConnectors(node).contains(outputPort)) { + String msg = String.format("Enqueue port %s is not present on this container", outputPort); + return new Status(StatusCode.BADREQUEST, msg); + } + } + } + return new Status(StatusCode.SUCCESS); + } + /** * Adds a flow entry onto the network node It runs various validity checks * and derive the final container flows merged entries that will be @@ -264,6 +318,15 @@ public class ForwardingRulesManager implements return new Status(StatusCode.NOTACCEPTABLE, INVALID_FLOW_ENTRY); } + // Operational check: input, output and queue ports presence check and + // action validation for this container + Status status = validateEntry(flowEntry); + if (!status.isSuccess()) { + String msg = String.format("%s: %s", INVALID_FLOW_ENTRY, status.getDescription()); + log.warn("{}: {}", msg, flowEntry); + return new Status(StatusCode.NOTACCEPTABLE, msg); + } + /* * Redundant Check: Check if the request is a redundant one from the * same application the flowEntry is equal to an existing one. Given we @@ -422,6 +485,15 @@ public class ForwardingRulesManager implements return new Status(StatusCode.SUCCESS, msg); } + // Operational check: input, output and queue ports presence check and + // action validation for this container + Status status = validateEntry(newFlowEntry); + if (!status.isSuccess()) { + String msg = String.format("Modify: %s: %s", INVALID_FLOW_ENTRY, status.getDescription()); + log.warn("{}: {}", msg, newFlowEntry); + return new Status(StatusCode.NOTACCEPTABLE, msg); + } + /* * Conflict Check: Verify the new entry would not conflict with an * existing one. This is a loose check on the previous original flow @@ -1121,7 +1193,10 @@ public class ForwardingRulesManager implements List list = new ArrayList(groupFlows.get(groupName)); toBeRemoved = list.size(); for (FlowEntryInstall entry : list) { - Status status = this.removeEntry(entry.getOriginal(), false); + // since this is the entry that was stored in groupFlows + // it is already validated and merged + // so can call removeEntryInternal directly + Status status = this.removeEntryInternal(entry, false); if (status.isSuccess()) { toBeRemoved -= 1; } else { @@ -1516,7 +1591,7 @@ public class ForwardingRulesManager implements @Override public Status addStaticFlow(FlowConfig config) { // Configuration object validation - Status status = config.validate(container); + Status status = config.validate(); if (!status.isSuccess()) { log.warn("Invalid Configuration for flow {}. The failure is {}", config, status.getDescription()); String error = "Invalid Configuration (" + status.getDescription() + ")"; @@ -1680,6 +1755,7 @@ public class ForwardingRulesManager implements config.setStatus(StatusCode.SUCCESS.toString()); break; default: + break; } } } @@ -1775,7 +1851,7 @@ public class ForwardingRulesManager implements } // Validity Check - Status status = newFlowConfig.validate(container); + Status status = newFlowConfig.validate(); if (!status.isSuccess()) { String msg = "Invalid Configuration (" + status.getDescription() + ")"; newFlowConfig.setStatus(msg); @@ -1855,7 +1931,7 @@ public class ForwardingRulesManager implements } } if (target != null) { - Status status = target.validate(container); + Status status = target.validate(); if (!status.isSuccess()) { log.warn(status.getDescription()); return status; @@ -2757,6 +2833,7 @@ public class ForwardingRulesManager implements this.reinstallAllFlowEntries(); break; default: + break; } // Update our configuration DB diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index e48ebbc057..e6e935c920 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -202,6 +202,16 @@ public class BindingIndependentConnector implements // DataModification, DataObject> source) { DataModificationTransaction target = biDataService.beginTransaction(); LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier()); + for (InstanceIdentifier entry : source.getRemovedConfigurationData()) { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); + target.removeConfigurationData(biEntry); + LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry); + } + for (InstanceIdentifier entry : source.getRemovedOperationalData()) { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); + target.removeOperationalData(biEntry); + LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry); + } for (Entry, DataObject> entry : source.getUpdatedConfigurationData() .entrySet()) { Entry biEntry = mappingService @@ -216,16 +226,7 @@ public class BindingIndependentConnector implements // target.putOperationalData(biEntry.getKey(), biEntry.getValue()); LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry); } - for (InstanceIdentifier entry : source.getRemovedConfigurationData()) { - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); - target.removeConfigurationData(biEntry); - LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry); - } - for (InstanceIdentifier entry : source.getRemovedOperationalData()) { - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); - target.removeOperationalData(biEntry); - LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry); - } + return target; } @@ -233,6 +234,24 @@ public class BindingIndependentConnector implements // DataModification source) { org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService .beginTransaction(); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { + try { + + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeConfigurationData(baEntry); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}.", entry, e); + } + } + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { + try { + + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeOperationalData(baEntry); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}.", entry, e); + } + } for (Entry entry : source .getUpdatedConfigurationData().entrySet()) { try { @@ -254,24 +273,6 @@ public class BindingIndependentConnector implements // LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e); } } - for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { - try { - - InstanceIdentifier baEntry = mappingService.fromDataDom(entry); - target.removeConfigurationData(baEntry); - } catch (DeserializationException e) { - LOG.error("Ommiting from BA transaction: {}.", entry, e); - } - } - for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { - try { - - InstanceIdentifier baEntry = mappingService.fromDataDom(entry); - target.removeOperationalData(baEntry); - } catch (DeserializationException e) { - LOG.error("Ommiting from BA transaction: {}.", entry, e); - } - } return target; } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend index 1159d5650e..6b5f5acb19 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -50,7 +50,7 @@ class BrokerConfigActivator implements AutoCloseable { broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders.fromSchemaService(schemaService))); dataService = new DataBrokerImpl(); - dataService.setExecutor(broker.getExecutor()); + //dataService.setExecutor(broker.getExecutor()); dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java index f380c27373..d8315568be 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -9,19 +9,14 @@ package org.opendaylight.controller.sal.dom.broker.impl; import static com.google.common.base.Preconditions.checkState; -import java.io.Console; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.concurrent.Future; -import javax.activation.UnsupportedDataTypeException; - import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.md.sal.common.api.data.DataReader; @@ -34,11 +29,9 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; -import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; @@ -47,7 +40,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; @@ -180,18 +172,25 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { NormalizedDataModification normalized = new NormalizedDataModification(original); - for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { - normalized.putDeepConfigurationData(entry.getKey(), entry.getValue()); - } - for (Entry entry : original.getUpdatedOperationalData().entrySet()) { - normalized.putDeepOperationalData(entry.getKey(), entry.getValue()); - } + LOG.trace("Transaction: {} Removed Configuration {}, Removed Operational {}", original.getIdentifier(), + original.getRemovedConfigurationData(), original.getRemovedConfigurationData()); + LOG.trace("Transaction: {} Created Configuration {}, Created Operational {}", original.getIdentifier(), + original.getCreatedConfigurationData().entrySet(), original.getCreatedOperationalData().entrySet()); + LOG.trace("Transaction: {} Updated Configuration {}, Updated Operational {}", original.getIdentifier(), + original.getUpdatedConfigurationData().entrySet(), original.getUpdatedOperationalData().entrySet()); + for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { normalized.deepRemoveConfigurationData(entry); } for (InstanceIdentifier entry : original.getRemovedOperationalData()) { normalized.deepRemoveOperationalData(entry); } + for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { + normalized.putDeepConfigurationData(entry.getKey(), entry.getValue()); + } + for (Entry entry : original.getUpdatedOperationalData().entrySet()) { + normalized.putDeepOperationalData(entry.getKey(), entry.getValue()); + } return normalized; } @@ -359,7 +358,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator child : entryData.getChildren()) { - InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType()).toInstance(); + InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType()) + .toInstance(); if (child instanceof CompositeNode) { DataSchemaNode subSchema = schemaNodeFor(subEntryId); CompositeNode compNode = (CompositeNode) child; @@ -420,12 +421,13 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator mapOfSubValues = this.getValuesFromListSchema(listSubSchema, (CompositeNode) child); + Map mapOfSubValues = this.getValuesFromListSchema(listSubSchema, + (CompositeNode) child); if (mapOfSubValues != null) { - instanceId = InstanceIdentifier.builder(entryKey).nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance(); + instanceId = InstanceIdentifier.builder(entryKey) + .nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance(); } - } - else if (subSchema instanceof ContainerSchemaNode) { + } else if (subSchema instanceof ContainerSchemaNode) { ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema; instanceId = InstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance(); } @@ -436,13 +438,13 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator getValuesFromListSchema (ListSchemaNode listSchema, CompositeNode entryData) { + private Map getValuesFromListSchema(ListSchemaNode listSchema, CompositeNode entryData) { List keyDef = listSchema.getKeyDefinition(); - if (keyDef != null && ! keyDef.isEmpty()) { + if (keyDef != null && !keyDef.isEmpty()) { Map map = new HashMap(); for (QName key : keyDef) { List> data = entryData.get(key); - if (data != null && ! data.isEmpty()) { + if (data != null && !data.isEmpty()) { for (Node nodeData : data) { if (nodeData instanceof SimpleNode) { map.put(key, data.get(0).getValue()); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index f6c39bf8c5..0683c45ebc 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -94,14 +94,14 @@ public interface RestconfService { @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload); + public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/operations/{identifier:.+}") @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData invokeRpc(@PathParam("identifier") String identifier, @DefaultValue("") String noPayload); + public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload); @GET @Path("/config/{identifier:.+}") diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index 482dcf8e8b..9b5c507811 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -356,7 +356,6 @@ class ControllerContext implements SchemaServiceListener { private def toUriString(Object object) { if(object === null) return ""; -// return object.toString.replace("/",URI_SLASH_PLACEHOLDER) return URLEncoder.encode(object.toString,URI_ENCODING_CHAR_SET) } @@ -620,6 +619,13 @@ class ControllerContext implements SchemaServiceListener { decodedPathArgs.add(URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET)) } return decodedPathArgs + } + + def urlPathArgDecode(String pathArg) { + if (pathArg !== null) { + return URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET) + } + return null } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend index cfbce736fb..e09dc7ac01 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend @@ -230,10 +230,7 @@ class RestconfImpl implements RestconfService { } override invokeRpc(String identifier, CompositeNode payload) { - val rpc = identifier.rpcDefinition - if (rpc === null) { - throw new ResponseException(NOT_FOUND, "RPC does not exist."); - } + val rpc = resolveIdentifierInInvokeRpc(identifier) if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) { val value = normalizeNode(payload, rpc.input, null) val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path")) @@ -267,7 +264,22 @@ class RestconfImpl implements RestconfService { if (!noPayload.nullOrEmpty) { throw new ResponseException(UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type."); } - return callRpc(identifier.rpcDefinition, null) + val rpc = resolveIdentifierInInvokeRpc(identifier) + return callRpc(rpc, null) + } + + def resolveIdentifierInInvokeRpc(String identifier) { + if (identifier.indexOf("/") === -1) { + val identifierDecoded = identifier.urlPathArgDecode + val rpc = identifierDecoded.rpcDefinition + if (rpc !== null) { + return rpc + } + throw new ResponseException(NOT_FOUND, "RPC does not exist."); + } + val slashErrorMsg = String.format("Identifier %n%s%ncan't contain slash character (/). + + If slash is part of identifier name then use %2F placeholder.",identifier) + throw new ResponseException(NOT_FOUND, slashErrorMsg); } private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) { diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java index 07c08129db..4a6a291e6a 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java @@ -269,7 +269,7 @@ public class Activator extends ComponentActivatorAbstractBase { c.add(createServiceDependency() .setService(IFlowProgrammerNotifier.class) .setCallbacks("setFlowProgrammerNotifier", - "unsetsetFlowProgrammerNotifier") + "unsetFlowProgrammerNotifier") .setRequired(false)); c.add(createServiceDependency() diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java index ba2394131d..3a4a192fc9 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java @@ -19,6 +19,7 @@ package org.opendaylight.controller.sal.core; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -65,11 +66,9 @@ public class Path implements Serializable { for (int i = 0; i < edges.size() - 1; i++) { Edge current = edges.get(i); Edge next = edges.get(i + 1); - if (!current.getHeadNodeConnector().getNode() - .equals( - next.getTailNodeConnector() - .getNode())) { + if (!current.getHeadNodeConnector().getNode().equals(next.getTailNodeConnector().getNode())) { sequential = false; + break; } } } else if (edges.size() == 0) { @@ -155,10 +154,10 @@ public class Path implements Serializable { * getter method for the Path * * - * @return Return the list of edges that constitue the Path + * @return Return the list of edges that constitute the Path */ public List getEdges() { - return this.edges; + return (edges == null) ? Collections.emptyList() : new ArrayList(edges); } @Override @@ -171,18 +170,23 @@ public class Path implements Serializable { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } Path other = (Path) obj; if (edges == null) { - if (other.edges != null) + if (other.edges != null) { return false; - } else if (!edges.equals(other.edges)) + } + } else if (!edges.equals(other.edges)) { return false; + } return true; }