From: Giovanni Meo Date: Tue, 30 Jul 2013 15:46:00 +0000 (+0000) Subject: Merge "Added uses to extends list. Groupings in YANG are used through key word uses... X-Git-Tag: releasepom-0.1.0~255 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=2f14a41bbd09010114116aef1499641f7251bf83;hp=b4d71d207d8c5e96a8b6dac8804a4a0de03812a8 Merge "Added uses to extends list. Groupings in YANG are used through key word uses. YANG elements which contains uses "something" are now generated as interface which extends "something"." --- diff --git a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java index 5aa8f10706..f600e6b2ac 100644 --- a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java +++ b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java @@ -323,9 +323,13 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw logger.debug("hostFind(): Host found for IP: {}", networkAddress.getHostAddress()); return host; } + /* host is not found, initiate a discovery */ + hostFinder.find(networkAddress); + /* Also add this host to ARPPending List for any potential retries */ + AddtoARPPendingList(networkAddress); logger.debug("hostFind(): Host Not Found for IP: {}, Inititated Host Discovery ...", networkAddress.getHostAddress()); @@ -447,7 +451,13 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw private void replaceHost(InetAddress networkAddr, HostNodeConnector removedHost, HostNodeConnector newHost) { newHost.initArpSendCountDown(); if (hostsDB.replace(networkAddr, removedHost, newHost)) { - logger.debug("Host move occurred. Old Host:{}, New Host: {}", removedHost, newHost); + logger.debug("Host move occurred: Old Host IP:{}, New Host IP: {}", removedHost.getNetworkAddress() + .getHostAddress(), newHost.getNetworkAddress().getHostAddress()); + logger.debug("Old Host MAC: {}, New Host MAC: {}", + HexEncode.bytesToHexString(removedHost.getDataLayerAddressBytes()), + HexEncode.bytesToHexString(newHost.getDataLayerAddressBytes())); + // Display the Old and New HostNodeConnectors also + logger.debug("Old {}, New {}", removedHost, newHost); } else { /* * Host replacement has failed, do the recovery @@ -518,8 +528,9 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw @Override public void hostListener(HostNodeConnector host) { + logger.debug("ARP received for Host: IP {}, MAC {}, {}", host.getNetworkAddress().getHostAddress(), + HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host); if (hostExists(host)) { - logger.debug("ARP received for Host: {}", host); HostNodeConnector existinghost = hostsDB.get(host.getNetworkAddress()); existinghost.initArpSendCountDown(); return; @@ -532,6 +543,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw private void notifyHostLearnedOrRemoved(HostNodeConnector host, boolean add) { // Update listeners if any if (newHostNotify != null) { + logger.debug("Notifying Applications for Host {} Being {}", host.getNetworkAddress().getHostAddress(), + add ? "Added" : "Deleted"); synchronized (this.newHostNotify) { for (IfNewHostNotify ta : newHostNotify) { try { @@ -563,6 +576,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } if (topologyManager != null && p != null && h != null) { + logger.debug("Notifying Topology Manager for Host {} Being {}", h.getNetworkAddress().getHostAddress(), + add ? "Added" : "Deleted"); if (add == true) { Tier tier = new Tier(1); switchManager.setNodeProp(node, tier); @@ -881,8 +896,12 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw for (int i = 0; i < failedARPReqList.size(); i++) { ARPPending arphost; arphost = failedARPReqList.get(i); - logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress()); - hostFinder.find(arphost.getHostIP()); + if (hostFinder == null) { + logger.warn("ARPHandler Services are not available on subnet addition"); + continue; + } + logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress()); + hostFinder.find(arphost.getHostIP()); } } } @@ -898,18 +917,23 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw if (arphost.getSent_count() < switchManager.getHostRetryCount()) { /* * No reply has been received of first ARP Req, send the - * next one + * next one. Before sending the ARP, check if ARPHandler + * is available or not */ + if (hostFinder == null) { + logger.warn("ARPHandler Services are not available for Outstanding ARPs"); + continue; + } hostFinder.find(arphost.getHostIP()); arphost.sent_count++; logger.debug("ARP Sent from ARPPending List, IP: {}", arphost.getHostIP().getHostAddress()); } else if (arphost.getSent_count() >= switchManager.getHostRetryCount()) { /* - * Two ARP requests have been sent without receiving a + * ARP requests have been sent without receiving a * reply, remove this from the pending list */ removePendingARPFromList(i); - logger.debug("ARP reply not received after two attempts, removing from Pending List IP: {}", + logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}", arphost.getHostIP().getHostAddress()); /* * Add this host to a different list which will be processed @@ -973,6 +997,15 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) }); } host.setArpSendCountDown(arp_cntdown); + if (hostFinder == null) { + /* + * If hostfinder is not available, then can't send the + * probe. However, continue the age out the hosts since + * we don't know if the host is indeed out there or not. + */ + logger.warn("ARPHandler is not avaialable, can't send the probe"); + continue; + } hostFinder.probe(host); } } @@ -1254,6 +1287,12 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw for (int i = 0; i < failedARPReqList.size(); i++) { arphost = failedARPReqList.get(i); logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress()); + if (hostFinder == null) { + logger.warn("ARPHandler is not available at interface up"); + logger.warn("Since this event is missed, host(s) connected to interface {} may not be discovered", + nodeConnector); + continue; + } hostFinder.find(arphost.getHostIP()); } HostNodeConnector host = inactiveStaticHosts.get(nodeConnector); diff --git a/opendaylight/hosttracker_new/api/src/main/java/org/opendaylight/controller/hosttracker/Entity.java b/opendaylight/hosttracker_new/api/src/main/java/org/opendaylight/controller/hosttracker/Entity.java index 7c98e9505b..924d0717e9 100644 --- a/opendaylight/hosttracker_new/api/src/main/java/org/opendaylight/controller/hosttracker/Entity.java +++ b/opendaylight/hosttracker_new/api/src/main/java/org/opendaylight/controller/hosttracker/Entity.java @@ -33,9 +33,12 @@ package org.opendaylight.controller.hosttracker; +import java.net.InetAddress; import java.util.Date; +import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.utils.NetUtils; /** * An entity on the network is a visible trace of a device that corresponds to a @@ -218,6 +221,19 @@ public class Entity implements Comparable { return true; } + public HostNodeConnector toHostNodeConnector() { + try { + NodeConnector n = this.getPort(); + InetAddress ip = InetAddress.getByAddress(NetUtils.intToByteArray4(this.getIpv4Address())); + byte[] macAddr = NetUtils.longToByteArray6(this.getMacAddress()); + HostNodeConnector nc = new HostNodeConnector(macAddr, ip, n, + (short) 0); + return nc; + } catch (Exception e) { + return null; + } + } + @Override public String toString() { return "Entity [macAddress=" + macAddress + ", ipv4Address=" diff --git a/opendaylight/hosttracker_new/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/DeviceManagerImpl.java b/opendaylight/hosttracker_new/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/DeviceManagerImpl.java index 0a6c2713dd..95d33ceef9 100755 --- a/opendaylight/hosttracker_new/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/DeviceManagerImpl.java +++ b/opendaylight/hosttracker_new/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/DeviceManagerImpl.java @@ -52,6 +52,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -77,6 +78,8 @@ import org.opendaylight.controller.sal.core.Host; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.State; import org.opendaylight.controller.sal.core.Tier; import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.controller.sal.packet.ARP; @@ -96,6 +99,7 @@ import org.opendaylight.controller.sal.utils.NetUtils; import org.opendaylight.controller.sal.utils.SingletonTask; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; +import org.opendaylight.controller.switchmanager.IInventoryListener; import org.opendaylight.controller.switchmanager.ISwitchManager; import org.opendaylight.controller.topologymanager.ITopologyManager; import org.opendaylight.controller.topologymanager.ITopologyManagerAware; @@ -110,7 +114,8 @@ import org.slf4j.LoggerFactory; * @author readams */ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, - IListenDataPacket, ITopologyManagerAware, IfIptoHost { + IListenDataPacket, ITopologyManagerAware, IfIptoHost, + IInventoryListener { protected static Logger logger = LoggerFactory .getLogger(DeviceManagerImpl.class); @@ -222,6 +227,7 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, */ protected ConcurrentHashMap deviceMap; + protected ConcurrentHashMap inactiveStaticDevices; /** * Counter used to generate device keys */ @@ -305,7 +311,9 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, /** * Using the IfNewHostNotify to notify listeners of host changes. */ - private Set newHostNotify = Collections.synchronizedSet(new HashSet()); + private Set newHostNotify = Collections + .synchronizedSet(new HashSet()); + /** * A device update event to be dispatched */ @@ -445,11 +453,11 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, // Dependency injection // ******************** - void setNewHostNotify(IfNewHostNotify obj){ + void setNewHostNotify(IfNewHostNotify obj) { this.newHostNotify.add(obj); } - void unsetNewHostNotify(IfNewHostNotify obj){ + void unsetNewHostNotify(IfNewHostNotify obj) { this.newHostNotify.remove(obj); } @@ -496,6 +504,7 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, secondaryIndexMap = new HashMap, DeviceIndex>(); deviceMap = new ConcurrentHashMap(); + inactiveStaticDevices = new ConcurrentHashMap(); classStateMap = new ConcurrentHashMap(); apComparator = new AttachmentPointComparator(); @@ -804,11 +813,11 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, if (inPkt == null) { return PacketResult.IGNORED; } -// try { -// throw new Exception("Sample"); -// } catch (Exception e) { -// logger.error("Sample stack trace", e); -// } + // try { + // throw new Exception("Sample"); + // } catch (Exception e) { + // logger.error("Sample stack trace", e); + // } Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt); Ethernet eth; @@ -1469,14 +1478,16 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, protected void notifyListeners(List listeners, DeviceUpdate update) { - // Topology update is for some reason outside of listeners registry - // logic + // Topology update is for some reason outside of listeners registry + // logic Entity[] ents = update.device.getEntities(); - Entity e = ents[ents.length-1]; + Entity e = ents[ents.length - 1]; + NodeConnector p = e.getPort(); Node node = p.getNode(); Host h = null; try { + byte[] mac = NetUtils.longToByteArray6(e.getMacAddress()); DataLinkAddress dla = new EthernetAddress( mac); @@ -1487,7 +1498,7 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, } catch (ConstructionException ce) { p = null; h = null; - } catch (UnknownHostException ue){ + } catch (UnknownHostException ue) { p = null; h = null; } @@ -1512,19 +1523,20 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, return; } /** - * TODO: IfNewHostNotify is needed for current controller API. - * Adding logic so that existing apps (like SimpleForwardingManager) - * work. IDeviceListener adds additional methods and uses IListener's - * callback ordering. The two interfaces need to be merged. + * TODO: IfNewHostNotify is needed for current controller API. Adding + * logic so that existing apps (like SimpleForwardingManager) work. + * IDeviceListener adds additional methods and uses IListener's callback + * ordering. The two interfaces need to be merged. */ - for (IfNewHostNotify notify : newHostNotify){ + for (IfNewHostNotify notify : newHostNotify) { switch (update.change) { case ADD: notify.notifyHTClient(update.device.toHostNodeConnector()); break; case DELETE: - notify.notifyHTClientHostRemoved(update.device.toHostNodeConnector()); + notify.notifyHTClientHostRemoved(update.device + .toHostNodeConnector()); break; case CHANGE: } @@ -1953,19 +1965,21 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, } } } + /** - * Send update notifications to listeners. - * IfNewHostNotify listeners need to remove old device and add new device. + * Send update notifications to listeners. IfNewHostNotify listeners need to + * remove old device and add new device. + * * @param device * @param oldDevice */ - protected void sendDeviceMovedNotification(Device device, Device oldDevice){ - for (IfNewHostNotify notify : newHostNotify){ - notify.notifyHTClientHostRemoved(oldDevice.toHostNodeConnector()); - notify.notifyHTClient(device.toHostNodeConnector()); - } - sendDeviceMovedNotification(device); + protected void sendDeviceMovedNotification(Device device, Device oldDevice) { + for (IfNewHostNotify notify : newHostNotify) { + notify.notifyHTClientHostRemoved(oldDevice.toHostNodeConnector()); + notify.notifyHTClient(device.toHostNodeConnector()); } + sendDeviceMovedNotification(device); + } /** * this method will reclassify and reconcile a device - possibilities are - @@ -2041,7 +2055,7 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, return mac; } - /** + /** * Accepts an IPv4 address in a byte array and returns the corresponding * 32-bit integer value. * @@ -2205,7 +2219,7 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, Set nc = new HashSet(); while (i.hasNext()) { Device device = i.next(); - if(device.isStaticHost()) + if (device.isStaticHost()) nc.add(device.toHostNodeConnector()); } return nc; @@ -2213,22 +2227,38 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, @Override public Set getInactiveStaticHosts() { - // TODO Auto-generated method stub - return null; + Collection devices = Collections + .unmodifiableCollection(inactiveStaticDevices.values()); + Iterator i = devices.iterator(); + Set nc = new HashSet(); + while (i.hasNext()) { + Entity ent = i.next(); + nc.add(ent.toHostNodeConnector()); + + } + return nc; } @Override public Status addStaticHost(String networkAddress, String dataLayerAddress, NodeConnector nc, String vlan) { Long mac = HexEncode.stringToLong(dataLayerAddress); - try{ + try { InetAddress addr = InetAddress.getByName(networkAddress); int ip = toIPv4Address(addr.getAddress()); Entity e = new Entity(mac, Short.valueOf(vlan), ip, nc, new Date()); - Device d = this.learnDeviceByEntity(e); - d.setStaticHost(true); + + if (switchManager.isNodeConnectorEnabled(e.getPort())) { + Device d = this.learnDeviceByEntity(e); + d.setStaticHost(true); + } else { + logger.debug( + "Switch or switchport is not up, adding host {} to inactive list", + addr.getHostName()); + inactiveStaticDevices.put(e.getPort(), e); + } return new Status(StatusCode.SUCCESS); - }catch(UnknownHostException e){ + } catch (UnknownHostException e) { return new Status(StatusCode.INTERNALERROR); } } @@ -2237,26 +2267,122 @@ public class DeviceManagerImpl implements IDeviceService, IEntityClassListener, public Status removeStaticHost(String networkAddress) { Integer addr; try { - addr = toIPv4Address(InetAddress.getByName(networkAddress).getAddress()); + addr = toIPv4Address(InetAddress.getByName(networkAddress) + .getAddress()); } catch (UnknownHostException e) { return new Status(StatusCode.NOTFOUND, "Host does not exist"); } - Iterator di = this.getDeviceIteratorForQuery(null, null, addr, null); - List listeners = deviceListeners - .getOrderedListeners(); - while(di.hasNext()){ + Iterator di = this.getDeviceIteratorForQuery(null, null, addr, + null); + List listeners = deviceListeners.getOrderedListeners(); + while (di.hasNext()) { Device d = di.next(); - if(d.isStaticHost()){ + if (d.isStaticHost()) { deleteDevice(d); for (IfNewHostNotify notify : newHostNotify) notify.notifyHTClientHostRemoved(d.toHostNodeConnector()); for (IDeviceListener listener : listeners) - listener.deviceRemoved(d); + listener.deviceRemoved(d); + } + } + //go through inactive entites. + Set inactive = this.getInactiveStaticHosts(); + for(HostNodeConnector nc : inactive){ + Integer ip =toIPv4Address(nc.getNetworkAddress().getAddress()); + if(ip.equals(addr)){ + this.inactiveStaticDevices.remove(nc.getnodeConnector()); } } + + return new Status(StatusCode.SUCCESS); } + @Override + public void notifyNode(Node node, UpdateType type, + Map propMap) { + if (node == null) + return; + List listeners = deviceListeners.getOrderedListeners(); + switch (type) { + case REMOVED: + logger.debug("Received removed node {}", node); + for (Entry d : deviceMap.entrySet()) { + Device device = d.getValue(); + HostNodeConnector host = device.toHostNodeConnector(); + if (host.getnodeconnectorNode().equals(node)) { + logger.debug("Node: {} is down, remove from Hosts_DB", node); + deleteDevice(device); + for (IfNewHostNotify notify : newHostNotify) + notify.notifyHTClientHostRemoved(host); + for (IDeviceListener listener : listeners) + listener.deviceRemoved(device); + } + } + break; + default: + break; + } + } + + @Override + public void notifyNodeConnector(NodeConnector nodeConnector, + UpdateType type, Map propMap) { + if (nodeConnector == null) + return; + List listeners = deviceListeners.getOrderedListeners(); + boolean up = false; + switch (type) { + case ADDED: + up = true; + break; + case REMOVED: + break; + case CHANGED: + State state = (State) propMap.get(State.StatePropName); + if ((state != null) && (state.getValue() == State.EDGE_UP)) { + up = true; + } + break; + default: + return; + } + + if (up) { + logger.debug("handleNodeConnectorStatusUp {}", nodeConnector); + + Entity ent = inactiveStaticDevices.get(nodeConnector); + Device device = this.learnDeviceByEntity(ent); + if(device!=null){ + HostNodeConnector host = device.toHostNodeConnector(); + if (host != null) { + inactiveStaticDevices.remove(nodeConnector); + for (IfNewHostNotify notify : newHostNotify) + notify.notifyHTClient(host); + for (IDeviceListener listener : listeners) + listener.deviceAdded(device); + } else { + logger.debug("handleNodeConnectorStatusDown {}", nodeConnector); + } + } + }else{ + // remove all devices on the node that went down. + for (Entry entry : deviceMap.entrySet()) { + Device device = entry.getValue(); + HostNodeConnector host = device.toHostNodeConnector(); + if (host.getnodeConnector().equals(nodeConnector)) { + deleteDevice(device); + for (IfNewHostNotify notify : newHostNotify) + notify.notifyHTClientHostRemoved(host); + for (IDeviceListener listener : listeners) + listener.deviceRemoved(device); + } + } + + } + } + + /** * For testing: consolidate the store NOW */ diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java index 6c26af2dc7..4daa591ba1 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -27,9 +26,8 @@ import org.slf4j.LoggerFactory; * This Class forms the vendor specific IPv6 Flow Match messages as well as * processes the vendor specific IPv6 Stats Reply message. * - * For message creation, it parses the user entered IPv6 match fields, creates - * a sub-message for each field which are later used to form the complete - * message. + * For message creation, it parses the user entered IPv6 match fields, creates a + * sub-message for each field which are later used to form the complete message. * * For message processing, it parses the incoming message and reads each field * of the message and stores in appropriate field of V6Match object. @@ -44,8 +42,7 @@ public class V6Match extends OFMatch implements Cloneable { protected short inputPortMask; protected byte[] dataLayerSourceMask; protected byte[] dataLayerDestinationMask; - protected short dataLayerVirtualLanMask; - protected byte dataLayerVirtualLanPriorityCodePointMask; + protected int dataLayerVirtualLanTCIMask; protected short dataLayerTypeMask; protected byte networkTypeOfServiceMask; protected byte networkProtocolMask; @@ -57,7 +54,9 @@ public class V6Match extends OFMatch implements Cloneable { protected MatchFieldState inputPortState; protected MatchFieldState dlSourceState; protected MatchFieldState dlDestState; - protected MatchFieldState dlVlanState; + protected MatchFieldState dlVlanIDState; + protected MatchFieldState dlVlanPCPState; + protected MatchFieldState dlVlanTCIState; protected MatchFieldState ethTypeState; protected MatchFieldState nwTosState; protected MatchFieldState nwProtoState; @@ -131,8 +130,7 @@ public class V6Match extends OFMatch implements Cloneable { this.dataLayerSourceMask = null; this.dataLayerDestinationMask = null; this.dataLayerTypeMask = 0; - this.dataLayerVirtualLanMask = 0; - this.dataLayerVirtualLanPriorityCodePointMask = 0; + this.dataLayerVirtualLanTCIMask = 0; this.networkTypeOfServiceMask = 0; this.networkProtocolMask = 0; this.transportSourceMask = 0; @@ -141,7 +139,9 @@ public class V6Match extends OFMatch implements Cloneable { this.inputPortState = MatchFieldState.MATCH_ABSENT; this.dlSourceState = MatchFieldState.MATCH_ABSENT; this.dlDestState = MatchFieldState.MATCH_ABSENT; - this.dlVlanState = MatchFieldState.MATCH_ABSENT; + this.dlVlanIDState = MatchFieldState.MATCH_ABSENT; + this.dlVlanPCPState = MatchFieldState.MATCH_ABSENT; + this.dlVlanTCIState = MatchFieldState.MATCH_ABSENT; this.ethTypeState = MatchFieldState.MATCH_ABSENT; this.nwTosState = MatchFieldState.MATCH_ABSENT; this.nwProtoState = MatchFieldState.MATCH_ABSENT; @@ -162,7 +162,7 @@ public class V6Match extends OFMatch implements Cloneable { if (match.getNetworkSource() != 0) { InetAddress address = NetUtils.getInetAddress(match.getNetworkSource()); InetAddress mask = NetUtils.getInetNetworkMask(match.getNetworkSourceMaskLen(), false); - this.setNetworkDestination(address, mask); + this.setNetworkSource(address, mask); } else { this.nwSrcState = MatchFieldState.MATCH_ABSENT; } @@ -184,13 +184,15 @@ public class V6Match extends OFMatch implements Cloneable { } this.dataLayerSourceMask = null; - if (match.getDataLayerSource() != null && !NetUtils.isZeroMAC(match.getDataLayerSource())) { + if (match.getDataLayerSource() != null + && !NetUtils.isZeroMAC(match.getDataLayerSource())) { this.setDataLayerSource(match.getDataLayerSource(), null); } else { this.dlSourceState = MatchFieldState.MATCH_ABSENT; } this.dataLayerDestinationMask = null; - if (match.getDataLayerDestination() != null && !NetUtils.isZeroMAC(match.getDataLayerDestination())) { + if (match.getDataLayerDestination() != null + && !NetUtils.isZeroMAC(match.getDataLayerDestination())) { this.setDataLayerDestination(match.getDataLayerDestination(), null); } else { this.dlDestState = MatchFieldState.MATCH_ABSENT; @@ -204,27 +206,28 @@ public class V6Match extends OFMatch implements Cloneable { this.ethTypeState = MatchFieldState.MATCH_ABSENT; } - this.dataLayerVirtualLanMask = 0; + this.dataLayerVirtualLanTCIMask = 0; + this.dlVlanTCIState = MatchFieldState.MATCH_ABSENT; if (match.getDataLayerVirtualLan() != 0) { this.setDataLayerVirtualLan(match.getDataLayerVirtualLan(), (short) 0); } else { this.dataLayerVirtualLan = 0; - this.dlVlanState = MatchFieldState.MATCH_ABSENT; + this.dlVlanIDState = MatchFieldState.MATCH_ABSENT; } - this.dataLayerVirtualLanPriorityCodePointMask = 0; if (match.getDataLayerVirtualLanPriorityCodePoint() != 0) { - this.setDataLayerVirtualLanPriorityCodePoint(match - .getDataLayerVirtualLanPriorityCodePoint(), (byte) 0); + this.setDataLayerVirtualLanPriorityCodePoint( + match.getDataLayerVirtualLanPriorityCodePoint(), (byte) 0); } else { this.dataLayerVirtualLanPriorityCodePoint = 0; + this.dlVlanPCPState = MatchFieldState.MATCH_ABSENT; } this.networkProtocolMask = 0; if (match.getNetworkProtocol() != 0) { - this.setNetworkProtocol(this.networkProtocol = match - .getNetworkProtocol(), (byte) 0); + this.setNetworkProtocol( + this.networkProtocol = match.getNetworkProtocol(), (byte) 0); } else { this.networkProtocol = 0; this.nwProtoState = MatchFieldState.MATCH_ABSENT; @@ -232,8 +235,9 @@ public class V6Match extends OFMatch implements Cloneable { this.networkTypeOfServiceMask = 0; if (match.getNetworkTypeOfService() != 0) { - this.setNetworkTypeOfService(this.networkTypeOfService = match - .getNetworkTypeOfService(), (byte) 0); + this.setNetworkTypeOfService( + this.networkTypeOfService = match.getNetworkTypeOfService(), + (byte) 0); } else { this.networkTypeOfService = match.getNetworkTypeOfService(); this.nwTosState = MatchFieldState.MATCH_ABSENT; @@ -327,13 +331,47 @@ public class V6Match extends OFMatch implements Cloneable { return (ipv6ext_etype_msg.array()); } - private byte[] getIPv6ExtensionVlanIDMatchMsg(short VLAN) { - ByteBuffer ipv6ext_vlanid_msg = ByteBuffer.allocate(6); + private byte[] getVlanTCI(short dataLayerVirtualLanID, + byte dataLayerVirtualLanPriorityCodePoint) { + ByteBuffer vlan_tci = ByteBuffer.allocate(2); + int cfi = 1 << 12; // the cfi bit is in position 12 + int pcp = dataLayerVirtualLanPriorityCodePoint << 13; // the pcp fields + // have to move by + // 13 + int vlan_tci_int = pcp + cfi + dataLayerVirtualLanID; + vlan_tci.put((byte) (vlan_tci_int >> 8)); // bits 8 to 15 + vlan_tci.put((byte) vlan_tci_int); // bits 0 to 7 + return vlan_tci.array(); + } + + private byte[] getIPv6ExtensionVlanTCIMatchMsg(short dataLayerVirtualLanID, + byte dataLayerVirtualLanPriorityCodePoint) { + ByteBuffer ipv6ext_vlan_tci_msg = ByteBuffer.allocate(6); int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10, OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 0, 2); - ipv6ext_vlanid_msg.putInt(nxm_header); - ipv6ext_vlanid_msg.putShort(VLAN); - return (ipv6ext_vlanid_msg.array()); + ipv6ext_vlan_tci_msg.putInt(nxm_header); + ipv6ext_vlan_tci_msg.put(getVlanTCI(dataLayerVirtualLanID, + dataLayerVirtualLanPriorityCodePoint)); + return (ipv6ext_vlan_tci_msg.array()); + } + + private byte[] getIPv6ExtensionVlanTCIMatchWithMaskMsg( + short dataLayerVirtualLan, + byte dataLayerVirtualLanPriorityCodePoint, + int dataLayerVirtualLanTCIMask) { + ByteBuffer ipv6ext_vlan_tci_msg = ByteBuffer.allocate(8); + int nxm_header = getIPv6ExtensionMatchHeader(Extension_Types.OF_10, + OF_Match_Types.MATCH_OF_VLAN_TCI.getValue(), 1, 4); + ipv6ext_vlan_tci_msg.putInt(nxm_header); + ipv6ext_vlan_tci_msg.put(getVlanTCI(dataLayerVirtualLan, + dataLayerVirtualLanPriorityCodePoint)); + ipv6ext_vlan_tci_msg.put((byte) (dataLayerVirtualLanTCIMask >> 8)); // bits + // 8 + // to + // 15 + ipv6ext_vlan_tci_msg.put((byte) (dataLayerVirtualLanTCIMask)); // bits 0 + // to 7 + return (ipv6ext_vlan_tci_msg.array()); } private byte[] getIPv6ExtensionSrcIPv6MatchMsg(byte[] srcIpv6) { @@ -392,11 +430,10 @@ public class V6Match extends OFMatch implements Cloneable { ipv6ext_proto_msg.putInt(nxm_header); if (protocol == IPProtocols.ICMP.getValue()) { /* - * The front end passes the same protocol type values for IPv4 - * and IPv6 flows. For the Protocol types we allow in our GUI - * (ICMP, TCP, UDP), ICMP is the only one which is different for - * IPv6. It is 1 for v4 and 58 for v6 Therefore, we overwrite it - * here. + * The front end passes the same protocol type values for IPv4 and + * IPv6 flows. For the Protocol types we allow in our GUI (ICMP, + * TCP, UDP), ICMP is the only one which is different for IPv6. It + * is 1 for v4 and 58 for v6 Therefore, we overwrite it here. */ protocol = IPProtocols.ICMPV6.getValue(); } @@ -450,9 +487,11 @@ public class V6Match extends OFMatch implements Cloneable { } /** - * Sets this (V6Match) object's member variables based on a comma-separated key=value pair similar to OFMatch's fromString. + * Sets this (V6Match) object's member variables based on a comma-separated + * key=value pair similar to OFMatch's fromString. * - * @param match a key=value comma separated string. + * @param match + * a key=value comma separated string. */ @Override public void fromString(String match) throws IllegalArgumentException { @@ -497,17 +536,45 @@ public class V6Match extends OFMatch implements Cloneable { this.dataLayerType = U16.t(Integer.valueOf(values[1] .replaceFirst("0x", ""), 16)); } else { + this.dataLayerType = U16.t(Integer.valueOf(values[1])); } ethTypeState = MatchFieldState.MATCH_FIELD_ONLY; match_len += 6; } else if (values[0].equals(STR_DL_VLAN)) { this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1])); - dlVlanState = MatchFieldState.MATCH_FIELD_ONLY; - match_len += 6; + this.dlVlanIDState = MatchFieldState.MATCH_FIELD_ONLY; + // the variable dlVlanIDState is not really used as a flag + // for serializing and deserializing. Rather it is used as a + // flag + // to check if the vlan id is being set so that we can set the + // dlVlanTCIState appropriately. + if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len -= 2; + } else { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0x1fff; + match_len += 8; + } + this.wildcards &= ~OFPFW_DL_VLAN; } else if (values[0].equals(STR_DL_VLAN_PCP)) { this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short .valueOf(values[1])); + this.dlVlanPCPState = MatchFieldState.MATCH_FIELD_ONLY; + // the variable dlVlanPCPState is not really used as a flag + // for serializing and deserializing. Rather it is used as a + // flag + // to check if the vlan pcp is being set so that we can set the + // dlVlanTCIState appropriately. + if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len -= 2; + } else { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0xf000; + match_len += 8; + } this.wildcards &= ~OFPFW_DL_VLAN_PCP; } else if (values[0].equals(STR_NW_DST) || values[0].equals("ip_dst")) { @@ -524,7 +591,7 @@ public class V6Match extends OFMatch implements Cloneable { } this.setNetworkDestination(address, mask); } catch (UnknownHostException e) { - logger.error("",e); + logger.error("", e); } } else if (values[0].equals(STR_NW_SRC) || values[0].equals("ip_src")) { @@ -541,7 +608,7 @@ public class V6Match extends OFMatch implements Cloneable { } this.setNetworkSource(address, mask); } catch (UnknownHostException e) { - logger.error("",e); + logger.error("", e); } } else if (values[0].equals(STR_NW_PROTO)) { this.networkProtocol = U8.t(Short.valueOf(values[1])); @@ -571,8 +638,8 @@ public class V6Match extends OFMatch implements Cloneable { } /* - * In a V6 extension message action list should be preceded by a padding of 0 to - * 7 bytes based upon following formula. + * In a V6 extension message action list should be preceded by a padding + * of 0 to 7 bytes based upon following formula. */ pad_size = (short) (((match_len + 7) / 8) * 8 - match_len); @@ -602,9 +669,17 @@ public class V6Match extends OFMatch implements Cloneable { byte[] ipv6ext_srcmac_msg = getIPv6ExtensionSrcMacMatchMsg(this.dataLayerSource); data.put(ipv6ext_srcmac_msg); } - if (dlVlanState == MatchFieldState.MATCH_FIELD_ONLY) { - byte[] ipv6ext_vlan_id_msg = getIPv6ExtensionVlanIDMatchMsg(this.dataLayerVirtualLan); - data.put(ipv6ext_vlan_id_msg); + if (dlVlanTCIState == MatchFieldState.MATCH_FIELD_ONLY) { + byte[] ipv6ext_vlan_tci_msg = getIPv6ExtensionVlanTCIMatchMsg( + this.dataLayerVirtualLan, + this.dataLayerVirtualLanPriorityCodePoint); + data.put(ipv6ext_vlan_tci_msg); + } else if (dlVlanTCIState == MatchFieldState.MATCH_FIELD_WITH_MASK) { + byte[] ipv6ext_vlan_tci_msg_with_mask = getIPv6ExtensionVlanTCIMatchWithMaskMsg( + this.dataLayerVirtualLan, + this.dataLayerVirtualLanPriorityCodePoint, + this.dataLayerVirtualLanTCIMask); + data.put(ipv6ext_vlan_tci_msg_with_mask); } if (nwSrcState == MatchFieldState.MATCH_FIELD_ONLY) { byte[] ipv6ext_src_ipv6_msg = getIPv6ExtensionSrcIPv6MatchMsg(this.nwSrc @@ -728,33 +803,69 @@ public class V6Match extends OFMatch implements Cloneable { this.match_len += 6; } + private short getVlanID(byte firstByte, byte secondByte) { + short vlan_id_mask_firstByte = 0x0f;// this is the mask for the first + // byte + short vlan_id_mask_secondByte = 0xff;// this is the mask for the second + // byte + int vlanPart1 = (firstByte & vlan_id_mask_firstByte) << 8; + int vlanPart2 = secondByte & vlan_id_mask_secondByte; + return (short) (vlanPart1 + vlanPart2); + } + + private byte getVlanPCP(byte pcpByte) { + short vlan_pcp_mask = 0xe0;// this is the vlan pcp mask + int pcp_int = pcpByte & vlan_pcp_mask; + return (byte) (pcp_int >> 5); + } + private void readVlanTci(ByteBuffer data, int nxmLen, boolean hasMask) { - short vlan_mask = 0xfff; if (hasMask) { if ((nxmLen != 2 * 2) || (data.remaining() < 2 * 2)) { return; - } else { - short vlan = data.getShort(); - vlan &= vlan_mask; - super.setDataLayerVirtualLan(vlan); - this.dataLayerVirtualLanMask = data.getShort(); - this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK; + } + else { + byte firstByte = data.get(); + byte secondByte = data.get(); + this.dataLayerVirtualLanTCIMask = data.getShort() & 0xffff; // we + // need + // the + // last + // 16 + // bits + // check the mask now + if ((this.dataLayerVirtualLanTCIMask & 0x0fff) != 0) { + // if its a vlan id mask + // extract the vlan id + super.setDataLayerVirtualLan(getVlanID(firstByte, + secondByte)); + } else { + this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match + } + if ((this.dataLayerVirtualLanTCIMask & 0xe000) != 0) { + // else if its a vlan pcp mask + // extract the vlan pcp + super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte)); + } else { + this.wildcards ^= (1 << 20); + } + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 8; - this.wildcards ^= (1 << 20); } } else { if ((nxmLen != 2) || (data.remaining() < 2)) { return; - } else { - short vlan = data.getShort(); - vlan &= vlan_mask; - super.setDataLayerVirtualLan(vlan); - this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY; + } + else { + // get the vlan pcp + byte firstByte = data.get(); + byte secondByte = data.get(); + super.setDataLayerVirtualLanPriorityCodePoint(getVlanPCP(firstByte)); + super.setDataLayerVirtualLan(getVlanID(firstByte, secondByte)); + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 6; } } - - this.wildcards ^= (1 << 1); // Sync with 0F 1.0 Match } private void readIpTos(ByteBuffer data, int nxmLen, boolean hasMask) { @@ -812,7 +923,8 @@ public class V6Match extends OFMatch implements Cloneable { super.setNetworkSource(address); this.nwSrcState = MatchFieldState.MATCH_FIELD_ONLY; this.match_len += 8; - this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 Match + this.wildcards ^= (((1 << 6) - 1) << 8); // Sync with 0F 1.0 + // Match } } } @@ -832,8 +944,10 @@ public class V6Match extends OFMatch implements Cloneable { this.nwDstState = MatchFieldState.MATCH_FIELD_WITH_MASK; this.match_len += 12; int prefixlen = getNetworkMaskPrefixLength(mbytes); - this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match - this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0 Match + this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 + // Match + this.wildcards |= ((32 - prefixlen) << 14); // Sync with 0F 1.0 + // Match } } else { if ((nxmLen != 4) || (data.remaining() < 4)) { @@ -844,7 +958,8 @@ public class V6Match extends OFMatch implements Cloneable { int address = NetUtils.byteArray4ToInt(dbytes); super.setNetworkDestination(address); this.nwDstState = MatchFieldState.MATCH_FIELD_ONLY; - this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 Match + this.wildcards ^= (((1 << 6) - 1) << 14); // Sync with 0F 1.0 + // Match this.match_len += 8; } } @@ -979,9 +1094,7 @@ public class V6Match extends OFMatch implements Cloneable { + HexEncode.bytesToHexStringFormat(dataLayerSourceMask) + ", dataLayerDestinationMask=" + HexEncode.bytesToHexStringFormat(dataLayerDestinationMask) - + ", dataLayerVirtualLanMask=" + dataLayerVirtualLanMask - + ", dataLayerVirtualLanPriorityCodePointMask=" - + dataLayerVirtualLanPriorityCodePointMask + + ", dataLayerVirtualLanTCIMask=" + dataLayerVirtualLanTCIMask + ", dataLayerTypeMask=" + dataLayerTypeMask + ", networkTypeOfServiceMask=" + networkTypeOfServiceMask + ", networkProtocolMask=" + networkProtocolMask @@ -991,7 +1104,7 @@ public class V6Match extends OFMatch implements Cloneable { + ", dstIPv6SubnetMaskbits=" + dstIPv6SubnetMaskbits + ", inputPortState=" + inputPortState + ", dlSourceState=" + dlSourceState + ", dlDestState=" + dlDestState - + ", dlVlanState=" + dlVlanState + ", ethTypeState=" + + ", dlVlanTCIState=" + dlVlanTCIState + ", ethTypeState=" + ethTypeState + ", nwTosState=" + nwTosState + ", nwProtoState=" + nwProtoState + ", nwSrcState=" + nwSrcState + ", nwDstState=" + nwDstState + ", tpSrcState=" @@ -1001,8 +1114,9 @@ public class V6Match extends OFMatch implements Cloneable { /** * Read the data corresponding to the match field (received from the wire) - * Input: data: match field(s). Since match field is of variable length, the whole data that are passed in - * are assumed to fem0tbd.be the match fields. + * Input: data: match field(s). Since match field is of variable length, the + * whole data that are passed in are assumed to fem0tbd.be the match fields. + * * @param data */ @Override @@ -1018,8 +1132,8 @@ public class V6Match extends OFMatch implements Cloneable { /* * at least 4 bytes for each match header */ - logger.error("Invalid Vendor Extension Header. Size {}", data - .remaining()); + logger.error("Invalid Vendor Extension Header. Size {}", + data.remaining()); return; } /* @@ -1095,11 +1209,11 @@ public class V6Match extends OFMatch implements Cloneable { // Sync with 0F 1.0 Match if (super.getDataLayerType() == 0x800) { if (((this.wildcards >> 8) & 0x3f) == 0x3f) { - //ipv4 src processing + // ipv4 src processing this.wildcards ^= (((1 << 5) - 1) << 8); } if (((this.wildcards >> 14) & 0x3f) == 0x3f) { - //ipv4 dest processing + // ipv4 dest processing this.wildcards ^= (((1 << 5) - 1) << 14); } } else { @@ -1204,24 +1318,40 @@ public class V6Match extends OFMatch implements Cloneable { } } - public short getDataLayerVirtualLanMask() { - return dataLayerVirtualLanMask; - } - public void setDataLayerVirtualLan(short vlan, short mask) { + // mask is ignored as the code sets the appropriate mask super.dataLayerVirtualLan = vlan; - if (mask == 0) { - this.dlVlanState = MatchFieldState.MATCH_FIELD_ONLY; - this.match_len += 6; + this.dlVlanIDState = MatchFieldState.MATCH_FIELD_ONLY; + // the variable dlVlanIDState is not really used as a flag + // for serializing and deserializing. Rather it is used as a flag + // to check if the vlan id is being set so that we can set the + // dlVlanTCIState appropriately. + if (this.dlVlanPCPState != MatchFieldState.MATCH_ABSENT) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len -= 2; } else { - this.dataLayerVirtualLanMask = mask; - this.dlVlanState = MatchFieldState.MATCH_FIELD_WITH_MASK; - this.match_len += 8; + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0x1fff; + match_len += 8; } } public void setDataLayerVirtualLanPriorityCodePoint(byte pcp, byte mask) { + // mask is ignored as the code sets the appropriate mask super.dataLayerVirtualLanPriorityCodePoint = pcp; + this.dlVlanPCPState = MatchFieldState.MATCH_FIELD_ONLY; + // the variable dlVlanPCPState is not really used as a flag + // for serializing and deserializing. Rather it is used as a flag + // to check if the vlan pcp is being set so that we can set the + // dlVlanTCIState appropriately. + if (this.dlVlanIDState != MatchFieldState.MATCH_ABSENT) { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_ONLY; + match_len -= 2; + } else { + this.dlVlanTCIState = MatchFieldState.MATCH_FIELD_WITH_MASK; + this.dataLayerVirtualLanTCIMask = 0xf000; + match_len += 8; + } } public void setDataLayerType(short ethType, short mask) { @@ -1347,28 +1477,38 @@ public class V6Match extends OFMatch implements Cloneable { result = prime * result + Arrays.hashCode(dataLayerDestinationMask); result = prime * result + Arrays.hashCode(dataLayerSourceMask); result = prime * result + dataLayerTypeMask; - result = prime * result + dataLayerVirtualLanMask; - result = prime * result + dataLayerVirtualLanPriorityCodePointMask; - result = prime * result + ((dlDestState == null) ? 0 : dlDestState.hashCode()); - result = prime * result + ((dlSourceState == null) ? 0 : dlSourceState.hashCode()); - result = prime * result + ((dlVlanState == null) ? 0 : dlVlanState.hashCode()); + result = prime * result + dataLayerVirtualLanTCIMask; + result = prime * result + + ((dlDestState == null) ? 0 : dlDestState.hashCode()); + result = prime * result + + ((dlSourceState == null) ? 0 : dlSourceState.hashCode()); + result = prime * result + + ((dlVlanTCIState == null) ? 0 : dlVlanTCIState.hashCode()); result = prime * result + dstIPv6SubnetMaskbits; - result = prime * result + ((ethTypeState == null) ? 0 : ethTypeState.hashCode()); + result = prime * result + + ((ethTypeState == null) ? 0 : ethTypeState.hashCode()); result = prime * result + inputPortMask; - result = prime * result + ((inputPortState == null) ? 0 : inputPortState.hashCode()); + result = prime * result + + ((inputPortState == null) ? 0 : inputPortState.hashCode()); result = prime * result + match_len; result = prime * result + networkProtocolMask; result = prime * result + networkTypeOfServiceMask; result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode()); - result = prime * result + ((nwDstState == null) ? 0 : nwDstState.hashCode()); - result = prime * result + ((nwProtoState == null) ? 0 : nwProtoState.hashCode()); + result = prime * result + + ((nwDstState == null) ? 0 : nwDstState.hashCode()); + result = prime * result + + ((nwProtoState == null) ? 0 : nwProtoState.hashCode()); result = prime * result + ((nwSrc == null) ? 0 : nwSrc.hashCode()); - result = prime * result + ((nwSrcState == null) ? 0 : nwSrcState.hashCode()); - result = prime * result + ((nwTosState == null) ? 0 : nwTosState.hashCode()); + result = prime * result + + ((nwSrcState == null) ? 0 : nwSrcState.hashCode()); + result = prime * result + + ((nwTosState == null) ? 0 : nwTosState.hashCode()); result = prime * result + pad_size; result = prime * result + srcIPv6SubnetMaskbits; - result = prime * result + ((tpDstState == null) ? 0 : tpDstState.hashCode()); - result = prime * result + ((tpSrcState == null) ? 0 : tpSrcState.hashCode()); + result = prime * result + + ((tpDstState == null) ? 0 : tpDstState.hashCode()); + result = prime * result + + ((tpSrcState == null) ? 0 : tpSrcState.hashCode()); result = prime * result + transportDestinationMask; result = prime * result + transportSourceMask; return result; @@ -1395,21 +1535,15 @@ public class V6Match extends OFMatch implements Cloneable { if (dataLayerTypeMask != other.dataLayerTypeMask) { return false; } - if (dataLayerVirtualLanMask != other.dataLayerVirtualLanMask) { + if (dataLayerVirtualLanTCIMask != other.dataLayerVirtualLanTCIMask) { return false; } - if (dataLayerVirtualLanPriorityCodePointMask != other.dataLayerVirtualLanPriorityCodePointMask) { - return false; - } - if (dlDestState != other.dlDestState) { + if (dlVlanTCIState != other.dlVlanTCIState) { return false; } if (dlSourceState != other.dlSourceState) { return false; } - if (dlVlanState != other.dlVlanState) { - return false; - } if (dstIPv6SubnetMaskbits != other.dstIPv6SubnetMaskbits) { return false; } diff --git a/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java b/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java index 6afaf5f675..2898dde363 100644 --- a/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java +++ b/opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java @@ -6,9 +6,9 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.Arrays; + import org.junit.Assert; import org.junit.Test; -import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match; import org.openflow.protocol.OFMatch; public class V6ExtensionTest { @@ -119,6 +119,7 @@ public class V6ExtensionTest { match.fromString("ip_src=2001:ddd:3e1:1234:0000:1111:2222:3333/64"); match.fromString("ip_dst=2001:123:222:abc:111:aaa:1111:2222/64"); match.fromString("dl_vlan=10"); + match.fromString("dl_vpcp=1"); match.fromString("nw_proto=6"); match.fromString("nw_tos=100"); match.fromString("tp_dst=8080"); @@ -142,7 +143,8 @@ public class V6ExtensionTest { Assert.assertTrue(match.getDataLayerVirtualLan() == match2 .getDataLayerVirtualLan()); - // vlan pcp isn't part of write/read buffer + Assert.assertTrue(match.getDataLayerVirtualLanPriorityCodePoint() == match2 + .getDataLayerVirtualLanPriorityCodePoint()); Assert.assertTrue(match.getNetworkProtocol() == match2 .getNetworkProtocol()); Assert.assertTrue(match.getNetworkTypeOfService() == match2 diff --git a/opendaylight/sal/yang-prototype/code-generator/.gitignore b/opendaylight/sal/yang-prototype/code-generator/.gitignore index 40a85ffb28..acda8836ce 100644 --- a/opendaylight/sal/yang-prototype/code-generator/.gitignore +++ b/opendaylight/sal/yang-prototype/code-generator/.gitignore @@ -1 +1,2 @@ /.settings +/binding-java-api-generator/src/main/xtend-gen diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java index b6d8de62e6..f650004ba2 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java @@ -221,7 +221,7 @@ public final class TypeProviderImpl implements TypeProvider { final String strXPath = xpath.toString(); if (strXPath != null) { - if (strXPath.matches(".*//[.* | .*//].*")) { + if (strXPath.contains("[")) { returnType = Types.typeForClass(Object.class); } else { final Module module = findParentModuleForTypeDefinition(schemaContext, leafrefType); diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java index ce9f131b75..a8b3b487af 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java @@ -8,12 +8,14 @@ package org.opendaylight.controller.sal.binding.generator.impl; import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Set; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator; import org.opendaylight.controller.sal.binding.model.api.GeneratedProperty; @@ -73,9 +75,8 @@ public class GeneratedTypesTest { assertNotNull(inetTypesPath); assertNotNull(yangTypesPath); - // final SchemaContext context = resolveSchemaContextFromFiles( - // topologyPath, interfacesPath, ifTypePath, inetTypesPath, - // yangTypesPath); + // final SchemaContext context = resolveSchemaContextFromFiles(topologyPath, interfacesPath, ifTypePath, + // inetTypesPath, yangTypesPath); final SchemaContext context = resolveSchemaContextFromFiles(topologyPath, interfacesPath, inetTypesPath, yangTypesPath); assertNotNull(context); @@ -94,6 +95,7 @@ public class GeneratedTypesTest { GeneratedType gtDest = null; GeneratedType gtTunnel = null; GeneratedTransferObject gtTunnelKey = null; + GeneratedType gtTopology = null; for (final Type type : genTypes) { String name = type.getName(); if ("InterfaceKey".equals(name)) { @@ -110,6 +112,8 @@ public class GeneratedTypesTest { gtTunnel = (GeneratedType) type; } else if ("TunnelKey".equals(name)) { gtTunnelKey = (GeneratedTransferObject) type; + } else if ("Topology".equals(name)) { + gtTopology = (GeneratedType) type; } } @@ -120,6 +124,21 @@ public class GeneratedTypesTest { assertNotNull(gtDest); assertNotNull(gtTunnel); assertNotNull(gtTunnelKey); + assertNotNull(gtTopology); + + // Topology + final List gtTopoMethods = gtTopology.getMethodDefinitions(); + assertNotNull(gtTopoMethods); + MethodSignature condLeafref = null; + for (final MethodSignature method : gtTopoMethods) { + if (method.getName().equals("getCondLeafref")) { + condLeafref = method; + } + } + assertNotNull(condLeafref); + Type condLeafRT = condLeafref.getReturnType(); + assertNotNull(condLeafRT); + assertEquals("java.lang.Object", condLeafRT.getFullyQualifiedName()); // InterfaceId final List gtIfcKeyProps = gtIfcKey.getProperties(); @@ -133,8 +152,7 @@ public class GeneratedTypesTest { assertNotNull(ifcIdProp); Type ifcIdPropType = ifcIdProp.getReturnType(); assertNotNull(ifcIdPropType); - assertFalse(ifcIdPropType.equals("java.lang.Void")); - assertEquals(ifcIdPropType.getName(), "String"); + assertEquals("java.lang.String", ifcIdPropType.getFullyQualifiedName()); // Interface final List gtIfcMethods = gtIfc.getMethodDefinitions(); @@ -151,14 +169,14 @@ public class GeneratedTypesTest { assertNotNull(getIfcKey); Type getIfcKeyType = getIfcKey.getReturnType(); assertNotNull(getIfcKeyType); - assertFalse(getIfcKeyType.equals("java.lang.Void")); - assertEquals(getIfcKeyType.getName(), "InterfaceKey"); + assertNotSame("java.lang.Void", getIfcKeyType); + assertEquals("InterfaceKey", getIfcKeyType.getName()); assertNotNull(getHigherLayerIf); Type getHigherLayerIfType = getHigherLayerIf.getReturnType(); assertNotNull(getHigherLayerIfType); - assertFalse(getHigherLayerIfType.equals("java.lang.Void")); - assertEquals(getHigherLayerIfType.getName(), "List"); + assertNotSame("java.lang.Void", getHigherLayerIfType); + assertEquals("List", getHigherLayerIfType.getName()); // NetworkLink final List gtNetworkLinkMethods = gtNetworkLink.getMethodDefinitions(); @@ -172,8 +190,8 @@ public class GeneratedTypesTest { assertNotNull(getIfc); Type getIfcType = getIfc.getReturnType(); assertNotNull(getIfcType); - assertFalse(getIfcType.equals("java.lang.Void")); - assertEquals(getIfcType.getName(), "String"); + assertNotSame("java.lang.Void", getIfcType); + assertEquals("String", getIfcType.getName()); // SourceNode final List gtSourceMethods = gtSource.getMethodDefinitions(); @@ -187,8 +205,8 @@ public class GeneratedTypesTest { assertNotNull(getIdSource); Type getIdType = getIdSource.getReturnType(); assertNotNull(getIdType); - assertFalse(getIdType.equals("java.lang.Void")); - assertEquals(getIdType.getName(), "Uri"); + assertNotSame("java.lang.Void", getIdType); + assertEquals("Uri", getIdType.getName()); // DestinationNode final List gtDestMethods = gtDest.getMethodDefinitions(); @@ -202,8 +220,8 @@ public class GeneratedTypesTest { assertNotNull(getIdDest); Type getIdDestType = getIdDest.getReturnType(); assertNotNull(getIdDestType); - assertFalse(getIdDestType.equals("java.lang.Void")); - assertEquals(getIdDestType.getName(), "Uri"); + assertNotSame("java.lang.Void", getIdDestType); + assertEquals("Uri", getIdDestType.getName()); // Tunnel final List gtTunnelMethods = gtTunnel.getMethodDefinitions(); @@ -217,8 +235,8 @@ public class GeneratedTypesTest { assertNotNull(getTunnelKey); Type getTunnelKeyType = getTunnelKey.getReturnType(); assertNotNull(getTunnelKeyType); - assertFalse(getTunnelKeyType.equals("java.lang.Void")); - assertEquals(getTunnelKeyType.getName(), "TunnelKey"); + assertNotSame("java.lang.Void", getTunnelKeyType); + assertEquals("TunnelKey", getTunnelKeyType.getName()); // TunnelKey final List gtTunnelKeyProps = gtTunnelKey.getProperties(); @@ -232,8 +250,8 @@ public class GeneratedTypesTest { assertNotNull(tunnelId); Type tunnelIdType = tunnelId.getReturnType(); assertNotNull(tunnelIdType); - assertFalse(tunnelIdType.equals("java.lang.Void")); - assertEquals(tunnelIdType.getName(), "Uri"); + assertNotSame("java.lang.Void", tunnelIdType); + assertEquals("Uri", tunnelIdType.getName()); } @Test @@ -256,14 +274,11 @@ public class GeneratedTypesTest { assertEquals(3, simpleContainer.getMethodDefinitions().size()); assertEquals(2, nestedContainer.getMethodDefinitions().size()); - int setFooMethodCounter = 0; int getFooMethodCounter = 0; int getBarMethodCounter = 0; int getNestedContainerCounter = 0; String getFooMethodReturnTypeName = ""; - String setFooMethodInputParamName = ""; - String setFooMethodInputParamTypeName = ""; String getBarMethodReturnTypeName = ""; String getNestedContainerReturnTypeName = ""; for (final MethodSignature method : simpleContainer.getMethodDefinitions()) { @@ -272,13 +287,6 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); @@ -290,31 +298,20 @@ public class GeneratedTypesTest { } } - assertEquals(getFooMethodCounter, 1); - assertEquals(getFooMethodReturnTypeName, "Integer"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(setFooMethodCounter, 1); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "Integer"); + assertEquals(1, getFooMethodCounter); + assertEquals("Integer", getFooMethodReturnTypeName); - assertEquals(getBarMethodCounter, 1); - assertEquals(getBarMethodReturnTypeName, "String"); + assertEquals(1, getBarMethodCounter); + assertEquals("String", getBarMethodReturnTypeName); - assertEquals(getNestedContainerCounter, 1); - assertEquals(getNestedContainerReturnTypeName, "NestedContainer"); + assertEquals(1, getNestedContainerCounter); + assertEquals("NestedContainer", getNestedContainerReturnTypeName); - setFooMethodCounter = 0; getFooMethodCounter = 0; getBarMethodCounter = 0; - int setBarMethodCounter = 0; getFooMethodReturnTypeName = ""; - setFooMethodInputParamName = ""; - setFooMethodInputParamTypeName = ""; getBarMethodReturnTypeName = ""; - String setBarMethodInputParamName = ""; - String setBarMethodInputParamTypeName = ""; for (final MethodSignature method : nestedContainer.getMethodDefinitions()) { @@ -323,41 +320,17 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); } - - if (method.getName().equals("setBar")) { - setBarMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setBarMethodInputParamName = param.getName(); - setBarMethodInputParamTypeName = param.getType().getName(); - } } assertEquals(1, getFooMethodCounter); - assertEquals(getFooMethodReturnTypeName, "Short"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setFooMethodCounter); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "Short"); + assertEquals("Short", getFooMethodReturnTypeName); assertEquals(1, getBarMethodCounter); - assertEquals(getBarMethodReturnTypeName, "String"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setBarMethodCounter); - // assertEquals(setBarMethodInputParamName, "bar"); - // assertEquals(setBarMethodInputParamTypeName, "String"); + assertEquals("String", getBarMethodReturnTypeName); } @Test @@ -380,14 +353,11 @@ public class GeneratedTypesTest { assertEquals(3, simpleContainer.getMethodDefinitions().size()); assertEquals(2, nestedContainer.getMethodDefinitions().size()); - int setFooMethodCounter = 0; int getFooMethodCounter = 0; int getBarMethodCounter = 0; int getNestedContainerCounter = 0; String getFooMethodReturnTypeName = ""; - String setFooMethodInputParamName = ""; - String setFooMethodInputParamTypeName = ""; String getBarMethodReturnTypeName = ""; String getNestedContainerReturnTypeName = ""; for (final MethodSignature method : simpleContainer.getMethodDefinitions()) { @@ -396,13 +366,6 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); @@ -415,26 +378,18 @@ public class GeneratedTypesTest { } assertEquals(1, getFooMethodCounter); - assertEquals(getFooMethodReturnTypeName, "List"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setFooMethodCounter); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "List"); + assertEquals("List", getFooMethodReturnTypeName); assertEquals(1, getBarMethodCounter); - assertEquals(getBarMethodReturnTypeName, "String"); + assertEquals("String", getBarMethodReturnTypeName); assertEquals(1, getNestedContainerCounter); - assertEquals(getNestedContainerReturnTypeName, "NestedContainer"); + assertEquals("NestedContainer", getNestedContainerReturnTypeName); - setFooMethodCounter = 0; getFooMethodCounter = 0; getBarMethodCounter = 0; getFooMethodReturnTypeName = ""; - setFooMethodInputParamName = ""; - setFooMethodInputParamTypeName = ""; getBarMethodReturnTypeName = ""; for (final MethodSignature method : nestedContainer.getMethodDefinitions()) { @@ -443,13 +398,6 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); @@ -457,15 +405,10 @@ public class GeneratedTypesTest { } assertEquals(1, getFooMethodCounter); - assertEquals(getFooMethodReturnTypeName, "Short"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setFooMethodCounter); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "Short"); + assertEquals("Short", getFooMethodReturnTypeName); assertEquals(1, getBarMethodCounter); - assertEquals(getBarMethodReturnTypeName, "List"); + assertEquals("List", getBarMethodReturnTypeName); } @Test @@ -480,9 +423,6 @@ public class GeneratedTypesTest { assertNotNull(genTypes); assertEquals(6, genTypes.size()); - int genTypesCount = 0; - int genTOsCount = 0; - int listParentContainerMethodsCount = 0; int simpleListMethodsCount = 0; int listChildContainerMethodsCount = 0; @@ -517,7 +457,6 @@ public class GeneratedTypesTest { final GeneratedType genType = (GeneratedType) type; if (genType.getName().equals("ListParentContainer")) { listParentContainerMethodsCount = genType.getMethodDefinitions().size(); - genTypesCount++; } else if (genType.getName().equals("SimpleList")) { simpleListMethodsCount = genType.getMethodDefinitions().size(); final List methods = genType.getMethodDefinitions(); @@ -540,13 +479,10 @@ public class GeneratedTypesTest { getBarMethodCount++; } } - genTypesCount++; } else if (genType.getName().equals("ListChildContainer")) { listChildContainerMethodsCount = genType.getMethodDefinitions().size(); - genTypesCount++; } } else if (type instanceof GeneratedTransferObject) { - genTOsCount++; final GeneratedTransferObject genTO = (GeneratedTransferObject) type; final List properties = genTO.getProperties(); final List hashProps = genTO.getHashCodeIdentifiers(); diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang index 95de94375f..4fef1cddd2 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang @@ -1,6 +1,6 @@ module demo-topology { yang-version 1; - namespace ""; + namespace "urn:model.1demo-275topology.4.5.my"; prefix "tp"; organization "OPEN DAYLIGHT"; diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang index 2d6fc26287..be3119255e 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang @@ -57,6 +57,12 @@ module abstract-topology { UNIQUE topology identifier."; } + leaf cond-leafref { + type leafref { + path "/tp:topology/tp:network-nodes/tp:network-node[node-id = 'super-node']"; + } + } + container network-nodes { list network-node { key "node-id"; diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java index a394edd906..0c4683ed03 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java @@ -30,8 +30,11 @@ public final class BindingGeneratorUtil { if (packNameParts != null) { final StringBuilder builder = new StringBuilder(); for (int i = 0; i < packNameParts.length; ++i) { - if (JAVA_RESERVED_WORDS.contains(packNameParts[i])) { - packNameParts[i] = "_" + packNameParts[i]; + final String packNamePart = packNameParts[i]; + if (Character.isDigit(packNamePart.charAt(0))) { + packNameParts[i] = "_" + packNamePart; + } else if (JAVA_RESERVED_WORDS.contains(packNamePart)) { + packNameParts[i] = "_" + packNamePart; } if (i > 0) { builder.append("."); diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/pom.xml b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/pom.xml index fad725b1f8..86c8a8ad01 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/pom.xml @@ -7,6 +7,39 @@ 0.5.4-SNAPSHOT binding-java-api-generator + + + + org.eclipse.xtend + xtend-maven-plugin + 2.4.2 + + + + compile + + + ${basedir}/src/main/xtend-gen + + + + + + maven-clean-plugin + 2.4.1 + + + + ${basedir}/src/main/xtend-gen + + ** + + + + + + + org.opendaylight.controller @@ -25,5 +58,10 @@ junit junit + + org.eclipse.xtend + org.eclipse.xtend.lib + 2.4.2 + diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderClassDescriptor.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderClassDescriptor.java new file mode 100644 index 0000000000..72b4c87bf6 --- /dev/null +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderClassDescriptor.java @@ -0,0 +1,331 @@ +package org.opendaylight.controller.sal.java.api.generator; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject; +import org.opendaylight.controller.sal.binding.model.api.GeneratedType; +import org.opendaylight.controller.sal.binding.model.api.MethodSignature; +import org.opendaylight.controller.sal.binding.model.api.ParameterizedType; +import org.opendaylight.controller.sal.binding.model.api.Type; +import org.opendaylight.controller.yang.binding.Augmentable; + +public class BuilderClassDescriptor { + + private static final String GET_PREFIX = "get"; + private static final String JAVA_UTIL = "java.util"; + private static final String HASH_MAP = "HashMap"; + private static final String MAP = "Map"; + private static final String GET_AUGMENTATION_METHOD_NAME = "getAugmentation"; + + private final GeneratedType genType; + private Map imports; + private final String packageName; + private final String className; + private final Set methods; + private final Set fields; + private final List importsNames; + private FieldDeclaration augmentField; + + class TypeDeclaration { + + private final static String JAVA_LANG_PREFIX = "java.lang"; + private final String name; + private final TypeDeclaration[] generics; + + public TypeDeclaration(String pkg, String name, TypeDeclaration... generics) { + this.name = removeJavaLangPkgName(getRightTypeName(pkg, name)); + if (generics != null && generics.length > 0) { + this.generics = generics; + } else { + this.generics = null; + } + } + + public TypeDeclaration(final Type type) { + if (type == null) { + throw new IllegalArgumentException("Type cannot be NULL"); + } + + this.name = removeJavaLangPkgName(getRightTypeName(type.getPackageName(), type.getName())); + TypeDeclaration[] generics = null; + if (type instanceof ParameterizedType) { + final ParameterizedType pType = (ParameterizedType) type; + final Type[] actualTypeArguments = pType.getActualTypeArguments(); + generics = new TypeDeclaration[actualTypeArguments.length]; + for (int i = 0; i < actualTypeArguments.length; i++) { + generics[i] = new TypeDeclaration(actualTypeArguments[i].getPackageName(), + actualTypeArguments[i].getName()); + } + } + if (generics != null && generics.length > 0) { + this.generics = generics; + } else { + this.generics = null; + } + } + + private String removeJavaLangPkgName(final String typeName) { + if (typeName.startsWith(JAVA_LANG_PREFIX)) { + return typeName.substring(typeName.lastIndexOf(Constants.DOT) + 1); + } + return typeName; + } + + private String getRightTypeName(final String pkg, final String name) { + if (name == null) { + throw new IllegalArgumentException("Name cannot be NULL!"); + } + + if (imports == null) { + return name; + } + final String pkgFromImports = imports.get(name); + if (pkgFromImports == null || pkgFromImports.equals(pkg)) { + return name; + } + return (pkg == null ? "" : pkg) + Constants.DOT + name; + } + + public String getName() { + return name; + } + + public TypeDeclaration[] getGenerics() { + return generics; + } + + } + + class ParameterDeclaration { + + private final TypeDeclaration type; + private final String name; + + public ParameterDeclaration(TypeDeclaration type, String name) { + this.type = type; + this.name = name; + } + + public TypeDeclaration getType() { + return type; + } + + public String getName() { + return name; + } + + } + + class MethodDeclaration { + + private final TypeDeclaration returnType; + private final String name; + private final List parameters; + + public MethodDeclaration(final TypeDeclaration returnType, final String name, + final List parameters) { + this.returnType = returnType; + this.name = name; + if (parameters != null && !parameters.isEmpty()) { + this.parameters = parameters; + } else { + this.parameters = null; + } + } + + public TypeDeclaration getReturnType() { + return returnType; + } + + public String getName() { + return name; + } + + public List getParameters() { + return parameters; + } + + } + + class FieldDeclaration extends ParameterDeclaration { + + public FieldDeclaration(final TypeDeclaration type, final String name) { + super(type, name); + } + + } + + public BuilderClassDescriptor(final GeneratedType genType) { + if (genType == null) { + throw new IllegalArgumentException("Generated type reference cannot be NULL!"); + } + this.genType = genType; + this.imports = GeneratorUtil.createImports(genType); + addToImports(genType.getPackageName(), genType.getName()); + packageName = genType.getPackageName(); + className = genType.getName(); + methods = createMethods(); + fields = createFieldsFromMethods(); + importsNames = createImportsNames(); + } + + private Set createMethods() { + final Set methods = new LinkedHashSet<>(); + storeMethodsOfIfc(methods, genType); + storeMethodsOfImplementedIfcs(methods, genType.getImplements()); + return methods; + } + + private void storeMethodsOfIfc(final Set methodStorage, final GeneratedType ifc) { + for (MethodSignature methodSignature : ifc.getMethodDefinitions()) { + final List parameterDeclarations = getParameterDeclarationsFrom(methodSignature + .getParameters()); + methodStorage.add(new MethodDeclaration(new TypeDeclaration(methodSignature.getReturnType()), + methodSignature.getName(), parameterDeclarations)); + } + if (ifc.getEnclosedTypes() != null && !ifc.getEnclosedTypes().isEmpty()) { + addToImports(ifc.getPackageName(), ifc.getName() + ".*"); + } + } + + private List getParameterDeclarationsFrom(final List parameters) { + final List parameterDeclarations = new ArrayList<>(); + for (MethodSignature.Parameter mp : parameters) { + parameterDeclarations.add(new ParameterDeclaration(new TypeDeclaration(mp.getType()), mp.getName())); + } + return parameterDeclarations; + } + + private void storeMethodsOfImplementedIfcs(final Set methodStorage, + final List implementedIfcs) { + if (implementedIfcs == null || implementedIfcs.isEmpty()) { + return; + } + for (Type implementedIfc : implementedIfcs) { + if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) { + final GeneratedType ifc = ((GeneratedType) implementedIfc); + storeMethodsOfIfc(methodStorage, ifc); + storeMethodsOfImplementedIfcs(methodStorage, ifc.getImplements()); + } else if (implementedIfc.getFullyQualifiedName().equals(Augmentable.class.getName())) { + for (Method m : Augmentable.class.getMethods()) { + if (m.getName().equals(GET_AUGMENTATION_METHOD_NAME)) { + addToImports(JAVA_UTIL, HASH_MAP); + addToImports(JAVA_UTIL, MAP); + java.lang.reflect.Type returnType = m.getReturnType(); + final String fullyQualifiedName = ((Class) returnType).getName(); + addToImports(getPackageFrom(fullyQualifiedName), getNameFrom(fullyQualifiedName)); + TypeDeclaration augmentMethodType = new TypeDeclaration(getPackageFrom(fullyQualifiedName), + getNameFrom(fullyQualifiedName), new TypeDeclaration(genType)); + augmentField = createFieldFromGetMethod(new MethodDeclaration(augmentMethodType, m.getName(), + null)); + } + } + } + } + } + + private void addToImports(final String pkg, final String name) { + if (imports == null) { + imports = new LinkedHashMap<>(); + } + if (imports.get(name) == null) { + imports.put(name, pkg); + } + } + + private String getPackageFrom(final String fullyQualifiedName) { + final int lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT); + return lastDotIndex == -1 ? "" : fullyQualifiedName.substring(0, lastDotIndex); + } + + private String getNameFrom(final String fullyQualifiedName) { + final int lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT); + return lastDotIndex == -1 ? fullyQualifiedName : fullyQualifiedName.substring(lastDotIndex + 1); + } + + private Set createFieldsFromMethods() { + final Set result = new LinkedHashSet<>(); + + if (methods == null || methods.isEmpty()) { + return result; + } + + for (MethodDeclaration m : methods) { + final FieldDeclaration createdField = createFieldFromGetMethod(m); + if (createdField != null) { + result.add(createdField); + } + } + return result; + } + + private FieldDeclaration createFieldFromGetMethod(final MethodDeclaration method) { + if (method == null || method.getName() == null || method.getName().isEmpty()) { + return null; + } else if (method.getName().startsWith(GET_PREFIX)) { + final String fieldNameFromMethod = method.getName().substring(GET_PREFIX.length()); + final String fieldName = Character.toLowerCase(fieldNameFromMethod.charAt(0)) + + fieldNameFromMethod.substring(1); + return new FieldDeclaration(method.getReturnType(), fieldName); + } + return null; + } + + private List createImportsNames() { + final List result = new ArrayList<>(); + + if (imports == null || imports.isEmpty()) { + return result; + } + + for (Map.Entry entry : imports.entrySet()) { + final String typeName = entry.getKey(); + final String packageName = entry.getValue(); + result.add(packageName + Constants.DOT + typeName); + } + return result; + } + + public String getPackageName() { + return packageName; + } + + /** + * @return list of imports or empty list + */ + public List getImportsNames() { + return importsNames; + } + + public String getClassName() { + return className; + } + + /** + * @return set of methods or empty set + */ + public Set getFields() { + return fields; + } + + /** + * @return set of methods or empty set + */ + public Set getMethods() { + return methods; + } + + /** + * @return declaration of augment field or NULL + */ + public FieldDeclaration getAugmentField() { + return augmentField; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderGenerator.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderGenerator.java new file mode 100644 index 0000000000..07ee733253 --- /dev/null +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderGenerator.java @@ -0,0 +1,26 @@ +package org.opendaylight.controller.sal.java.api.generator; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + +import org.opendaylight.controller.sal.binding.model.api.CodeGenerator; +import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject; +import org.opendaylight.controller.sal.binding.model.api.GeneratedType; +import org.opendaylight.controller.sal.binding.model.api.Type; + +public final class BuilderGenerator implements CodeGenerator { + + public static final String FILE_NAME_SUFFIX = "Builder"; + + @Override + public Writer generate(Type type) throws IOException { + Writer writer = new StringWriter(); + if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) { + BuilderTemplate builerGeneratorXtend = new BuilderTemplate(); + writer.write(builerGeneratorXtend.generate(new BuilderClassDescriptor((GeneratedType) type)).toString()); + } + return writer; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderTemplate.xtend b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderTemplate.xtend new file mode 100644 index 0000000000..484fbfb3db --- /dev/null +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderTemplate.xtend @@ -0,0 +1,96 @@ +package org.opendaylight.controller.sal.java.api.generator + +import java.util.List +import java.util.Set + +class BuilderTemplate { + + val static BUILDER = 'Builder' + val static IMPL = 'Impl' + + def generate(BuilderClassDescriptor cd) ''' + package «cd.packageName»; + «IF !cd.importsNames.empty» + + «FOR in : cd.importsNames» + import «in»; + «ENDFOR» + «ENDIF» + + public class «cd.className»«BUILDER» { + + «fields(cd.fields, cd.augmentField)» + + «IF !cd.fields.empty» + «FOR field : cd.fields SEPARATOR '\n'» + public «cd.className»«BUILDER» set«field.name.toFirstUpper»(«field.type.name»«field.type.generics.print» «field.name») { + this.«field.name» = «field.name»; + return this; + } + «ENDFOR» + «ENDIF» + «IF cd.augmentField != null» + + public «cd.className»«BUILDER» add«cd.augmentField.name.toFirstUpper»(Class augmentationType, «cd.augmentField.type.name»«cd.augmentField.type.generics.print» augmentation) { + this.«cd.augmentField.name».put(augmentationType, augmentation); + return this; + } + «ENDIF» + + public «cd.className» build() { + return new «cd.className»«IMPL»(); + } + + private class «cd.className»«IMPL» implements «cd.className» { + + «fields(cd.fields, cd.augmentField)» + + private «cd.className»«IMPL»() { + «IF !cd.fields.empty» + «FOR field : cd.fields» + this.«field.name» = «cd.className»«BUILDER».this.«field.name»; + «ENDFOR» + «ENDIF» + «IF cd.augmentField != null» + this.«cd.augmentField.name».putAll(«cd.className»«BUILDER».this.«cd.augmentField.name»); + «ENDIF» + } + + «IF !cd.fields.empty» + «FOR field : cd.fields SEPARATOR '\n'» + @Override + public «field.type.name»«field.type.generics.print» get«field.name.toFirstUpper»() { + return «field.name»; + } + «ENDFOR» + «ENDIF» + «IF cd.augmentField != null» + + @Override + public E get«cd.augmentField.name.toFirstUpper»(Class augmentationType) { + if (augmentationType == null) { + throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!"); + } + return (E) «cd.augmentField.name».get(augmentationType); + } + «ENDIF» + + } + + } + ''' + + def private fields(Set fields, BuilderClassDescriptor.FieldDeclaration augmentField) ''' + «IF !fields.empty» + «FOR field : fields» + private «field.type.name»«field.type.generics.print» «field.name»; + «ENDFOR» + «ENDIF» + «IF augmentField != null» + private Map, «augmentField.type.name»«augmentField.type.generics.print»> «augmentField.name» = new HashMap<>(); + «ENDIF» + ''' + + def private print(List generics) '''«IF generics != null && !generics.empty»<«FOR generic : generics SEPARATOR ', '»«generic.name»«ENDFOR»>«ENDIF»''' + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/Constants.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/Constants.java index bcc17906d6..8f5c456f87 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/Constants.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/Constants.java @@ -24,6 +24,8 @@ final class Constants { public static final String GAP = " "; public static final String COMMA = ","; + public static final String DOT = "."; + public static final String ASTERISK = "*"; public static final String NL = "\n"; public static final String SC = ";"; public static final String TAB = " "; diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/GeneratorJavaFile.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/GeneratorJavaFile.java index 55b8d777b7..1d2e60f511 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/GeneratorJavaFile.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/GeneratorJavaFile.java @@ -23,6 +23,7 @@ public final class GeneratorJavaFile { private final CodeGenerator interfaceGenerator; private final ClassCodeGenerator classGenerator; private final EnumGenerator enumGenerator; + private final BuilderGenerator builderGenerator; private final Set genTypes; private final Set genTransferObjects; @@ -35,6 +36,7 @@ public final class GeneratorJavaFile { this.enumerations = new HashSet<>(); this.classGenerator = new ClassCodeGenerator(); this.enumGenerator = new EnumGenerator(); + this.builderGenerator = new BuilderGenerator(); } public GeneratorJavaFile(final Set types, final Set genTransferObjects, @@ -42,6 +44,7 @@ public final class GeneratorJavaFile { this.interfaceGenerator = new InterfaceGenerator(); this.classGenerator = new ClassCodeGenerator(); this.enumGenerator = new EnumGenerator(); + this.builderGenerator = new BuilderGenerator(); this.genTypes = types; this.genTransferObjects = genTransferObjects; @@ -51,14 +54,19 @@ public final class GeneratorJavaFile { public List generateToFile(final File parentDirectory) throws IOException { final List result = new ArrayList<>(); for (GeneratedType type : genTypes) { - final File genFile = generateTypeToJavaFile(parentDirectory, type, interfaceGenerator); + final File genFile = generateTypeToJavaFile(parentDirectory, type, interfaceGenerator, ""); + final File genBuilderFile = generateTypeToJavaFile(parentDirectory, type, builderGenerator, + BuilderGenerator.FILE_NAME_SUFFIX); if (genFile != null) { result.add(genFile); } + if (genBuilderFile != null) { + result.add(genBuilderFile); + } } for (GeneratedTransferObject transferObject : genTransferObjects) { - final File genFile = generateTypeToJavaFile(parentDirectory, transferObject, classGenerator); + final File genFile = generateTypeToJavaFile(parentDirectory, transferObject, classGenerator, ""); if (genFile != null) { result.add(genFile); @@ -66,7 +74,7 @@ public final class GeneratorJavaFile { } for (Enumeration enumeration : enumerations) { - final File genFile = generateTypeToJavaFile(parentDirectory, enumeration, enumGenerator); + final File genFile = generateTypeToJavaFile(parentDirectory, enumeration, enumGenerator, ""); if (genFile != null) { result.add(genFile); @@ -76,7 +84,7 @@ public final class GeneratorJavaFile { return result; } - private File generateTypeToJavaFile(final File parentDir, final Type type, final CodeGenerator generator) + private File generateTypeToJavaFile(final File parentDir, final Type type, final CodeGenerator generator, String fileNameSuffix) throws IOException { if (parentDir == null) { log.warn("Parent Directory not specified, files will be generated " @@ -95,7 +103,7 @@ public final class GeneratorJavaFile { if (!packageDir.exists()) { packageDir.mkdirs(); } - final File file = new File(packageDir, type.getName() + ".java"); + final File file = new File(packageDir, type.getName() + fileNameSuffix + ".java"); try (final FileWriter fw = new FileWriter(file)) { file.createNewFile(); diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/controller/sal/java/api/generator/test/GeneratorJavaFileTest.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/controller/sal/java/api/generator/test/GeneratorJavaFileTest.java index db42d32fe6..6a38050a4e 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/controller/sal/java/api/generator/test/GeneratorJavaFileTest.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/controller/sal/java/api/generator/test/GeneratorJavaFileTest.java @@ -90,10 +90,13 @@ public class GeneratorJavaFileTest { + "controller" + FS + "gen").list(); List filesList = Arrays.asList(files); - assertEquals(3, files.length); + assertEquals(6, files.length); assertTrue(filesList.contains("Type1.java")); assertTrue(filesList.contains("Type2.java")); assertTrue(filesList.contains("Type3.java")); + assertTrue(filesList.contains("Type1Builder.java")); + assertTrue(filesList.contains("Type2Builder.java")); + assertTrue(filesList.contains("Type3Builder.java")); } @Ignore diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml deleted file mode 100644 index d4c5b05731..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - 4.0.0 - org.opendaylight.controller - code-generator-demo - 1.0 - jar - - - - org.antlr - antlr4 - 4.0 - - - org.opendaylight.controller - binding-generator-impl - - - org.opendaylight.controller - binding-java-api-generator - - - - - - - maven-assembly-plugin - 2.4 - - - jar-with-dependencies - - - - org.opendaylight.controller.yang.Demo - - - - - - make-assembly - package - - single - - - - - - - - diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java deleted file mode 100644 index ee548876d0..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.yang; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator; -import org.opendaylight.controller.sal.binding.generator.impl.BindingGeneratorImpl; -import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject; -import org.opendaylight.controller.sal.binding.model.api.GeneratedType; -import org.opendaylight.controller.sal.binding.model.api.Type; -import org.opendaylight.controller.sal.java.api.generator.GeneratorJavaFile; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.SchemaContext; -import org.opendaylight.controller.yang.parser.impl.YangParserImpl; - -public class Demo { - private static final String ERR_MSG = "2 parameters expected: 1. -f=, 2. -o="; - - public static void main(String[] args) throws Exception { - if (args.length != 2) { - System.err.println(ERR_MSG); - return; - } - - String inputFilesDir = null; - String outputFilesDir = null; - if (args[0].startsWith("-f=")) { - inputFilesDir = args[0].substring(3); - } else { - System.err.println("Missing input-folder declaration (-f=)"); - } - - if (args[1].startsWith("-o=")) { - outputFilesDir = args[1].substring(3); - } else { - System.err.println("Missing output-folder declaration (-o=)"); - } - - File resourceDir = new File(inputFilesDir); - if (!resourceDir.exists()) { - throw new IllegalArgumentException( - "Specified input-folder does not exists: " - + resourceDir.getAbsolutePath()); - } - - final File outputFolder = new File(outputFilesDir); - if (!outputFolder.exists()) { - outputFolder.mkdirs(); - } - - String[] dirList = resourceDir.list(); - List inputFiles = new ArrayList(); - for (String fileName : dirList) { - inputFiles.add(new File(resourceDir, fileName)); - } - - final YangParserImpl parser = new YangParserImpl(); - final BindingGenerator bindingGenerator = new BindingGeneratorImpl(); - final Set modulesToBuild = parser.parseYangModels(inputFiles); - - final SchemaContext context = parser - .resolveSchemaContext(modulesToBuild); - final List types = bindingGenerator.generateTypes(context); - final Set typesToGenerate = new HashSet(); - final Set tosToGenerate = new HashSet(); - for (Type type : types) { - if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) { - typesToGenerate.add((GeneratedType) type); - } - - if (type instanceof GeneratedTransferObject) { - tosToGenerate.add((GeneratedTransferObject) type); - } else if (type instanceof GeneratedType) { - typesToGenerate.add((GeneratedType) type); - } - } - - final GeneratorJavaFile generator = new GeneratorJavaFile(typesToGenerate, tosToGenerate); - - generator.generateToFile(outputFolder); - System.out.println("Modules built: " + modulesToBuild.size()); - } -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang deleted file mode 100644 index 303edc295d..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang +++ /dev/null @@ -1,223 +0,0 @@ -module demo-topology { - yang-version 1; - namespace "urn:demo.simple-topology"; - prefix "tp"; - import simple-list-demo { prefix "simple"; revision-date 2008-01-01; } - import controller-network {prefix "cn";} - import mount {prefix "mnt";} - - organization "OPEN DAYLIGHT"; - contact "http://www.opendaylight.org/"; - - description " - This module contains the definitions of elements that creates network - topology i.e. definition of network nodes and links. This module is - not designed to be used solely for network representation. This module - SHOULD be used as base module in defining the network topology. - "; - - revision "2013-02-08"{ - reference " WILL BE DEFINED LATER"; - } - - - - - - deviation /base:system/base:user/base:type { - deviate add { - default "admin"; // new users are 'admin' by default - } - } - - deviation /base:system/base:name-server { - deviate replace { - max-elements 3; - } - } - - deviation "/base:system" { - deviate delete { - must "daytime or time"; - } - } - - - - - - - grouping target { - status "current"; - leaf address { - type inet:ip-address; - description "Target IP address"; - } - leaf port { - type inet:port-number; - description "Target port number"; - } - } - - augment "/cn:network/cn:topologies/cn:topology" { - container prefixes { - container "prefix" { - leaf id { - type string; - - description ""; - } - - leaf-list advertising-node-id { - type cn:node-ref; - - description ""; - } - } - } - mnt:mountpoint point { - mnt:target-ref target; - - } - } - - container peer { - container destination { - uses target; - } - } - - container topology { - - leaf ifType { - type enumeration { - enum ethernet; - enum atm; - } - } - leaf ifMTU { - type uint32; - } - must "ifType != 'ethernet' or " + - "(ifType = 'ethernet' and ifMTU = 1500)" { - error-message "An ethernet MTU must be 1500"; - } - - presence "test-presence"; - - description " - This is the model of abstract topology which contains only Network - Nodes and Network Links. Each topology MUST be identified by - unique topology-id for reason that the store could contain many - topologies. - "; - - leaf topology-id { - type string; - description " - It is presumed that datastore will contain many topologies. To - distinguish between topologies it is vital to have UNIQUE - topology identifier. - "; - } - - container network-nodes { - list network-node { - ordered-by system; - description "The list of network nodes defined for topology."; - - key "node-id"; - - leaf node-id { - type string; - description "The Topology identifier of network-node."; - } - - list network-interface { - key "interface-id"; - - leaf interface-id { - type uint8; - } - - leaf interface-address { - type string; - } - } - - container node-attributes { - description " - Additional attributes that can Network Node contains. - "; - - leaf geo-latitude { - type decimal64 { - fraction-digits 2; - } - config true; - } - - leaf geo-longitude { - type decimal64 { - fraction-digits 2; - } - config true; - } - } - } - } - - container network-links { - list network-link { - description " - The Network Link which is defined by Local (Source) and - Remote (Destination) Network Nodes. Every link MUST be - defined either by identifier and his local and remote - Network Nodes (in real applications it is common that many - links are originated from one node and end up in same - remote node). To ensure that we would always know to - distinguish between links, every link SHOULD have - identifier. - "; - key "link-id"; - - leaf link-id { - type string; - description ""; - } - - container source { - leaf node-id { - type string; - description "Source node identifier."; - } - } - - container destination { - leaf node-id { - type string; - description "Destination node identifier."; - } - } - - container link-attributes { - description "Aditional attributes that can Network Link contains."; - } - } - } - } - - rpc activate-software-image { - input { - leaf image-name { - type string; - } - } - output { - leaf status { - type string; - } - } - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang deleted file mode 100644 index 102529858b..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang +++ /dev/null @@ -1,80 +0,0 @@ -module types1 { - yang-version 1; - namespace "urn:simple.container.demo"; - prefix "t1"; - - - organization "Cisco"; - - contact "WILL-BE-DEFINED-LATER"; - - - leaf mybits { - type bits { - bit disable-nagle { - position 0; - } - bit auto-sense-speed { - position 1; - } - bit 10-Mb-only { - position 2; - } - } - default "auto-sense-speed"; - } - - container interfaces { - list ifEntry { - key "ifIndex"; - - leaf ifIndex { - type uint32; - } - leaf ifDescr { - type string; - } - leaf ifType { - type uint8; - } - leaf ifMtu { - type int32; - } - } - } - - - container topology { - leaf name { - type string; - } - } - - - - - - - -// typedef my-string { -// type string { -// length "0..4"; -// pattern "[0-9a-fA-F]*"; -// } -// } - - -// leaf completed { -// type types2:percent; -// } - -// leaf testleaf { -// type data:my-base-int32-type; -// } - -// leaf-list domain-search { -// type string; -// description "List of domain names to search"; -// } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang deleted file mode 100644 index a056bdb2e9..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang +++ /dev/null @@ -1,35 +0,0 @@ -module types2 { - yang-version 1; - namespace "urn:simple.types.data.demo"; - prefix "t2"; - - import types1 { - prefix "t1"; - } - - organization "Cisco"; - - contact "WILL-BE-DEFINED-LATER"; - - description "This is types-data test description"; - - revision "2013-02-27" { - reference " WILL BE DEFINED LATER"; - } - - - augment "/t1:interfaces/t1:ifEntry" { - when "t1:ifType='ds0'"; - leaf ds0ChannelNumber { - type string; - } - } - - typedef my-leaf-ref { - type leafref { - path "/t1:topology/t1:name"; - } - description "This type is used for leafs that reference network node instance."; - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang deleted file mode 100644 index 0d09259f3e..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang +++ /dev/null @@ -1,35 +0,0 @@ -module types3 { - yang-version 1; - namespace "urn:simple.types3.data.demo"; - prefix "scd"; - - organization "Cisco"; - - contact "WILL-BE-DEFINED-LATER"; - - description "This is types-data test description"; - - revision "2013-02-27" { - reference " WILL BE DEFINED LATER"; - } - - typedef my-decimal { - type decimal64 { - fraction-digits 2; - } - } - - typedef my-base-int32-type { - type int32 { - range "0..32"; - } - } - - typedef percent { - type uint8 { - range "0 .. 100"; - } - description "Percentage"; - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang index 8b576c3ce9..ca8507f9f4 100644 --- a/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang +++ b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang @@ -14,7 +14,7 @@ module controller-openflow-ne { augment "/cn:network/cn:network-elements/cn:network-element" { - container flow-tables { + container flow-tables2 { list flow-table { key "id"; diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/test-topology.yang b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/demo-topology.yang similarity index 66% rename from opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/test-topology.yang rename to opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/demo-topology.yang index 797ab2ced2..4fef1cddd2 100644 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/test-topology.yang +++ b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/demo-topology.yang @@ -1,13 +1,9 @@ -// vi: set smarttab sw=4 tabstop=4: -module abstract-topology { +module demo-topology { yang-version 1; - namespace "pre:simple.test.demo"; + namespace "urn:model.1demo-275topology.4.5.my"; prefix "tp"; - import ietf-inet-types { prefix "inet"; } - import abstract-prefixes { prefix "abs-pref"; } - - organization "OPEN DAYLIGHT"; + organization "OPEN DAYLIGHT"; contact "http://www.opendaylight.org/"; description " @@ -16,30 +12,9 @@ module abstract-topology { not designed to be used solely for network representation. This module SHOULD be used as base module in defining the network topology. "; - - revision "2012-02-08" { - reference " WILL BE DEFINED LATER"; - } - - typedef topology-id-ref { - type leafref { - path "/tp:topology/tp:topology-id"; - } - description "This type is used for leafs that reference topology identifier instance."; - } - typedef network-node-id-ref { - type leafref { - path "/tp:topology/tp:network-nodes/tp:network-node/tp:node-id"; - } - description "This type is used for leafs that reference network node instance."; - } - - typedef link-id-ref { - type leafref { - path "/tp:topology/tp:network-links/tp:network-link/tp:link-id"; - } - description "This type is used for leafs that reference network link instance."; + revision "2013-02-08"{ + reference " WILL BE DEFINED LATER"; } container topology { @@ -51,7 +26,7 @@ module abstract-topology { "; leaf topology-id { - type inet:uri; + type string; description " It is presumed that datastore will contain many topologies. To distinguish between topologies it is vital to have UNIQUE @@ -66,14 +41,40 @@ module abstract-topology { key "node-id"; leaf node-id { - type inet:uri; + type string; description "The Topology identifier of network-node."; } - - container attributes { + + list network-interface { + key "interface-id"; + + leaf interface-id { + type uint8; + } + + leaf interface-address { + type string; + } + } + + container node-attributes { description " Additional attributes that can Network Node contains. "; + + leaf geo-latitude { + type decimal64 { + fraction-digits 2; + } + config true; + } + + leaf geo-longitude { + type decimal64 { + fraction-digits 2; + } + config true; + } } } } @@ -93,30 +94,28 @@ module abstract-topology { key "link-id"; leaf link-id { - type inet:uri; + type string; description ""; } container source { leaf node-id { - type node-id-ref; + type string; description "Source node identifier."; } } container destination { leaf node-id { - type node-id-ref; + type string; description "Destination node identifier."; } } - container attributes { + container link-attributes { description "Aditional attributes that can Network Link contains."; } } } } - - //TODO: add base operations -} +} \ No newline at end of file diff --git a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java index 44ef804e2c..1d702c26d8 100644 --- a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java +++ b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java @@ -16,99 +16,254 @@ import java.util.Set; import org.opendaylight.controller.yang.common.QName; import org.opendaylight.controller.yang.model.api.*; +/** + * The Schema Context Util contains support methods for searching through Schema Context modules for specified schema + * nodes via Schema Path or Revision Aware XPath. The Schema Context Util is designed as mixin, + * so it is not instantiable. + * + * @author Lukas Sedlak + */ public final class SchemaContextUtil { private SchemaContextUtil() { } + /** + * Method attempts to find DataSchemaNode in Schema Context via specified Schema Path. The returned + * DataSchemaNode from method will be the node at the end of the SchemaPath. If the DataSchemaNode is not present + * in the Schema Context the method will return null. + *
+ * In case that Schema Context or Schema Path are not specified correctly (i.e. contains null + * values) the method will return IllegalArgumentException. + * + * @throws IllegalArgumentException + * + * @param context + * Schema Context + * @param schemaPath + * Schema Path to search for + * @return DataSchemaNode from the end of the Schema Path or + * null if the Node is not present. + */ public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final SchemaPath schemaPath) { - if (schemaPath != null) { - final Module module = resolveModuleFromSchemaPath(context, schemaPath); - final Queue prefixedPath = new LinkedList<>(schemaPath.getPath()); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } - if ((module != null) && (prefixedPath != null)) { - return findSchemaNodeForGivenPath(context, module, prefixedPath); - } + final Module module = resolveModuleFromSchemaPath(context, schemaPath); + final Queue prefixedPath = new LinkedList<>(schemaPath.getPath()); + + if ((module != null) && (prefixedPath != null)) { + return findSchemaNodeForGivenPath(context, module, prefixedPath); } return null; } + /** + * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to + * Non-conditional Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise the + * operation would fail and return null. + *
+ * The Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in path, + * because in this state the Schema Context is completely unaware of data state and will be not able to properly + * resolve XPath. If the XPath contains condition the method will return IllegalArgumentException. + *
+ * In case that Schema Context or Module or Revision Aware XPath contains null references the method + * will throw IllegalArgumentException + *
+ * If the Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in depending + * module in Schema Context the method will return specified Data Schema Node, otherwise the operation will fail + * and method will return null. + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param nonCondXPath Non Conditional Revision Aware XPath + * @return Returns Data Schema Node for specified Schema Context for given Non-conditional Revision Aware XPath, + * or null if the DataSchemaNode is not present in Schema Context. + */ public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final Module module, final RevisionAwareXPath nonCondXPath) { - if (nonCondXPath != null) { - final String strXPath = nonCondXPath.toString(); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (nonCondXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } - if (strXPath != null) { - if (strXPath.matches(".*//[.* | .*//].*")) { - // TODO: function to escape conditions in path - } - if (nonCondXPath.isAbsolute()) { - final Queue qnamedPath = xpathToQNamePath(context, module, strXPath); - if (qnamedPath != null) { - final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath); - return dataNode; - } + final String strXPath = nonCondXPath.toString(); + if (strXPath != null) { + if (strXPath.contains("[")) { + throw new IllegalArgumentException("Revision Aware XPath cannot contains condition!"); + } + if (nonCondXPath.isAbsolute()) { + final Queue qnamedPath = xpathToQNamePath(context, module, strXPath); + if (qnamedPath != null) { + final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath); + return dataNode; } } } return null; } + /** + * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to + * Non-conditional relative Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise + * the operation would fail and return null. + *
+ * The relative Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in + * path, because in this state the Schema Context is completely unaware of data state and will be not able to + * properly resolve XPath. If the XPath contains condition the method will return IllegalArgumentException. + *
+ * The Actual Schema Node MUST be specified correctly because from this Schema Node will search starts. If the + * Actual Schema Node is not correct the operation will simply fail, because it will be unable to find desired + * DataSchemaNode. + *
+ * In case that Schema Context or Module or Actual Schema Node or relative Revision Aware XPath contains + * null references the method will throw IllegalArgumentException + *
+ * If the Revision Aware XPath doesn't have flag isAbsolute == false the method will + * throw IllegalArgumentException. + *
+ * If the relative Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in + * depending module in Schema Context the method will return specified Data Schema Node, + * otherwise the operation will fail + * and method will return null. + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param actualSchemaNode Actual Schema Node + * @param relativeXPath Relative Non Conditional Revision Aware XPath + * @return DataSchemaNode if is present in specified Schema Context for given relative Revision Aware XPath, + * otherwise will return null. + */ public static DataSchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module, final SchemaNode actualSchemaNode, final RevisionAwareXPath relativeXPath) { - if ((actualSchemaNode != null) && (relativeXPath != null) && !relativeXPath.isAbsolute()) { + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (actualSchemaNode == null) { + throw new IllegalArgumentException("Actual Schema Node reference cannot be NULL!"); + } + if (relativeXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } + if (relativeXPath.isAbsolute()) { + throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, " + + "for non relative Revision Aware XPath use findDataSchemaNode method!"); + } - final SchemaPath actualNodePath = actualSchemaNode.getPath(); - if (actualNodePath != null) { - final Queue qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath); + final SchemaPath actualNodePath = actualSchemaNode.getPath(); + if (actualNodePath != null) { + final Queue qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath); - if (qnamePath != null) { - final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath); - return dataNode; - } + if (qnamePath != null) { + final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath); + return dataNode; } } - return null; } + /** + * Retrieve information from Schema Path and returns the module reference to which Schema Node belongs. The + * search for correct Module is based on namespace within the last item in Schema Path. If schema context + * contains module with namespace specified in last item of Schema Path, then operation will returns Module + * reference, otherwise returns null + *
+ * If Schema Context or Schema Node contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param schemaPath Schema Path + * @return Module reference for given Schema Path if module is present in Schema Context, + * otherwise returns null + */ private static Module resolveModuleFromSchemaPath(final SchemaContext context, final SchemaPath schemaPath) { - if ((schemaPath != null) && (schemaPath.getPath() != null)) { - final List path = schemaPath.getPath(); - if (!path.isEmpty()) { - final QName qname = path.get(path.size() - 1); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } + final List path = schemaPath.getPath(); + if (!path.isEmpty()) { + final QName qname = path.get(path.size() - 1); + + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); } } + return null; } + /** + * Returns the Yang Module from specified Schema Context in which the TypeDefinition is declared. If the + * TypeDefinition si not present in Schema Context then the method will return null + * + * If Schema Context or TypeDefinition contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param type Type Definition + * @return Yang Module in which the TypeDefinition is declared, if is not present, returns null. + */ public static Module findParentModuleForTypeDefinition(final SchemaContext context, final TypeDefinition type) { final SchemaPath schemaPath = type.getPath(); - if ((schemaPath != null) && (schemaPath.getPath() != null)) { - if (type instanceof ExtendedType) { - List path = schemaPath.getPath(); - final QName qname = path.get(path.size() - 1); - - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } - } else { - List path = schemaPath.getPath(); - final QName qname = path.get(path.size() - 2); + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } + final List qnamedPath = schemaPath.getPath(); + if (qnamedPath == null || qnamedPath.isEmpty()) { + throw new IllegalStateException("Schema Path contains invalid state of path parts." + + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name" + + "of path."); + } - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } + if (type instanceof ExtendedType) { + final QName qname = qnamedPath.get(qnamedPath.size() - 1); + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); + } + } else { + final QName qname = qnamedPath.get(qnamedPath.size() - 2); + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); } - } return null; } + /** + * Returns parent Yang Module for specified Schema Context in which Schema Node is declared. If the Schema Node + * is not present in Schema Context the operation will return null. + *
+ * If Schema Context or Schema Node contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param schemaNode Schema Node + * @return Yang Module for specified Schema Context and Schema Node, if Schema Node is NOT present, + * the method will returns null + */ public static Module findParentModule(final SchemaContext context, final SchemaNode schemaNode) { if (context == null) { throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); @@ -132,120 +287,246 @@ public final class SchemaContextUtil { return context.findModuleByNamespace(qname.getNamespace()); } + /** + * Method will attempt to find DataSchemaNode from specified Module and Queue of QNames through the Schema + * Context. The QNamed path could be defined across multiple modules in Schema Context so the method is called + * recursively. If the QNamed path contains QNames that are not part of any Module or Schema Context Path the + * operation will fail and returns null + *
+ * If Schema Context, Module or Queue of QNames refers to null values, + * the method will throws IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param qnamedPath Queue of QNames + * @return DataSchemaNode if is present in Module(s) for specified Schema Context and given QNamed Path, + * otherwise will return null. + */ private static DataSchemaNode findSchemaNodeForGivenPath(final SchemaContext context, final Module module, final Queue qnamedPath) { - if ((module != null) && (module.getNamespace() != null) && (qnamedPath != null)) { - DataNodeContainer nextNode = module; - final URI moduleNamespace = module.getNamespace(); - - QName childNodeQName; - DataSchemaNode schemaNode = null; - while ((nextNode != null) && !qnamedPath.isEmpty()) { - childNodeQName = qnamedPath.peek(); - if (childNodeQName != null) { - final URI childNodeNamespace = childNodeQName.getNamespace(); - - schemaNode = nextNode.getDataChildByName(childNodeQName); - if (schemaNode != null) { - if (schemaNode instanceof ContainerSchemaNode) { - nextNode = (ContainerSchemaNode) schemaNode; - } else if (schemaNode instanceof ListSchemaNode) { - nextNode = (ListSchemaNode) schemaNode; - } else if (schemaNode instanceof ChoiceNode) { - final ChoiceNode choice = (ChoiceNode) schemaNode; - qnamedPath.poll(); - if (!qnamedPath.isEmpty()) { - childNodeQName = qnamedPath.peek(); - nextNode = choice.getCaseNodeByName(childNodeQName); - schemaNode = (DataSchemaNode)nextNode; - } - } else { - nextNode = null; + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (module.getNamespace() == null) { + throw new IllegalArgumentException("Namespace for Module cannot contains NULL reference!"); + } + if (qnamedPath == null || qnamedPath.isEmpty()) { + throw new IllegalStateException("Schema Path contains invalid state of path parts." + + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name" + + "of path."); + } + + DataNodeContainer nextNode = module; + final URI moduleNamespace = module.getNamespace(); + + QName childNodeQName; + DataSchemaNode schemaNode = null; + while ((nextNode != null) && !qnamedPath.isEmpty()) { + childNodeQName = qnamedPath.peek(); + if (childNodeQName != null) { + final URI childNodeNamespace = childNodeQName.getNamespace(); + + schemaNode = nextNode.getDataChildByName(childNodeQName); + if (schemaNode != null) { + if (schemaNode instanceof ContainerSchemaNode) { + nextNode = (ContainerSchemaNode) schemaNode; + } else if (schemaNode instanceof ListSchemaNode) { + nextNode = (ListSchemaNode) schemaNode; + } else if (schemaNode instanceof ChoiceNode) { + final ChoiceNode choice = (ChoiceNode) schemaNode; + qnamedPath.poll(); + if (!qnamedPath.isEmpty()) { + childNodeQName = qnamedPath.peek(); + nextNode = choice.getCaseNodeByName(childNodeQName); + schemaNode = (DataSchemaNode) nextNode; } - } else if (!childNodeNamespace.equals(moduleNamespace)) { - final Module nextModule = context.findModuleByNamespace(childNodeNamespace); - schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath); - return schemaNode; + } else { + nextNode = null; } - qnamedPath.poll(); + } else if (!childNodeNamespace.equals(moduleNamespace)) { + final Module nextModule = context.findModuleByNamespace(childNodeNamespace); + schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath); + return schemaNode; } + qnamedPath.poll(); } - return schemaNode; } - return null; + return schemaNode; } + /** + * Transforms string representation of XPath to Queue of QNames. The XPath is split by "/" and for each part of + * XPath is assigned correct module in Schema Path. + *
+ * If Schema Context, Parent Module or XPath string contains null values, + * the method will throws IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param parentModule Parent Module + * @param xpath XPath String + * @return + */ private static Queue xpathToQNamePath(final SchemaContext context, final Module parentModule, final String xpath) { - final Queue path = new LinkedList<>(); - if (xpath != null) { - final String[] prefixedPath = xpath.split("/"); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (parentModule == null) { + throw new IllegalArgumentException("Parent Module reference cannot be NULL!"); + } + if (xpath == null) { + throw new IllegalArgumentException("XPath string reference cannot be NULL!"); + } - for (int i = 0; i < prefixedPath.length; ++i) { - if (!prefixedPath[i].isEmpty()) { - path.add(stringPathPartToQName(context, parentModule, prefixedPath[i])); - } + final Queue path = new LinkedList<>(); + final String[] prefixedPath = xpath.split("/"); + for (int i = 0; i < prefixedPath.length; ++i) { + if (!prefixedPath[i].isEmpty()) { + path.add(stringPathPartToQName(context, parentModule, prefixedPath[i])); } } return path; } + /** + * Transforms part of Prefixed Path as java String to QName. + *
+ * If the string contains module prefix separated by ":" (i.e. mod:container) this module is provided from from + * Parent Module list of imports. If the Prefixed module is present in Schema Context the QName can be + * constructed. + *
+ * If the Prefixed Path Part does not contains prefix the Parent's Module namespace is taken for construction of + * QName. + *
+ * If Schema Context, Parent Module or Prefixed Path Part refers to null the method will throw + * IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param parentModule Parent Module + * @param prefixedPathPart Prefixed Path Part string + * @return QName from prefixed Path Part String. + */ private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule, final String prefixedPathPart) { - if (parentModule != null && prefixedPathPart != null) { - if (prefixedPathPart.contains(":")) { - final String[] prefixedName = prefixedPathPart.split(":"); - final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); - if (module != null) { - return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); - } - } else { - return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (parentModule == null) { + throw new IllegalArgumentException("Parent Module reference cannot be NULL!"); + } + if (prefixedPathPart == null) { + throw new IllegalArgumentException("Prefixed Path Part cannot be NULL!"); + } + + if (prefixedPathPart.contains(":")) { + final String[] prefixedName = prefixedPathPart.split(":"); + final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); + if (module != null) { + return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); } + } else { + return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); } return null; } + /** + * Method will attempt to resolve and provide Module reference for specified module prefix. Each Yang module + * could contains multiple imports which MUST be associated with corresponding module prefix. The method simply + * looks into module imports and returns the module that is bounded with specified prefix. If the prefix is not + * present in module or the prefixed module is not present in specified Schema Context, + * the method will return null. + *
+ * If String prefix is the same as prefix of the specified Module the reference to this module is returned. + *
+ * If Schema Context, Module or Prefix are referring to null the method will return + * IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param prefix Module Prefix + * @return Module for given prefix in specified Schema Context if is present, otherwise returns null + */ private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, final String prefix) { - if ((module != null) && (prefix != null)) { - if (prefix.equals(module.getPrefix())) { - return module; - } + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (prefix == null) { + throw new IllegalArgumentException("Prefix string cannot be NULL!"); + } - final Set imports = module.getImports(); + if (prefix.equals(module.getPrefix())) { + return module; + } - for (final ModuleImport mi : imports) { - if (prefix.equals(mi.getPrefix())) { - return context.findModuleByName(mi.getModuleName(), mi.getRevision()); - } + final Set imports = module.getImports(); + for (final ModuleImport mi : imports) { + if (prefix.equals(mi.getPrefix())) { + return context.findModuleByName(mi.getModuleName(), mi.getRevision()); } } return null; } + /** + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param relativeXPath Non conditional Revision Aware Relative XPath + * @param leafrefSchemaPath Schema Path for Leafref + * @return + */ private static Queue resolveRelativeXPath(final SchemaContext context, final Module module, final RevisionAwareXPath relativeXPath, final SchemaPath leafrefSchemaPath) { final Queue absolutePath = new LinkedList<>(); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (relativeXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } + if (relativeXPath.isAbsolute()) { + throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, " + + "for non relative Revision Aware XPath use findDataSchemaNode method!"); + } + if (leafrefSchemaPath == null) { + throw new IllegalArgumentException("Schema Path reference for Leafref cannot be NULL!"); + } - if ((module != null) && (relativeXPath != null) && !relativeXPath.isAbsolute() && (leafrefSchemaPath != null)) { - final String strXPath = relativeXPath.toString(); - if (strXPath != null) { - final String[] xpaths = strXPath.split("/"); - - if (xpaths != null) { - int colCount = 0; - while (xpaths[colCount].contains("..")) { - ++colCount; + final String strXPath = relativeXPath.toString(); + if (strXPath != null) { + final String[] xpaths = strXPath.split("/"); + if (xpaths != null) { + int colCount = 0; + while (xpaths[colCount].contains("..")) { + ++colCount; + } + final List path = leafrefSchemaPath.getPath(); + if (path != null) { + int lenght = path.size() - colCount - 1; + for (int i = 0; i < lenght; ++i) { + absolutePath.add(path.get(i)); } - final List path = leafrefSchemaPath.getPath(); - if (path != null) { - int lenght = path.size() - colCount - 1; - for (int i = 0; i < lenght; ++i) { - absolutePath.add(path.get(i)); - } - for (int i = colCount; i < xpaths.length; ++i) { - absolutePath.add(stringPathPartToQName(context, module, xpaths[i])); - } + for (int i = colCount; i < xpaths.length; ++i) { + absolutePath.add(stringPathPartToQName(context, module, xpaths[i])); } } }