From: Giovanni Meo Date: Tue, 26 Nov 2013 15:55:15 +0000 (+0000) Subject: Merge "Fix bug 153: change the key container-config to ContainerConfig in the contain... X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~338 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=a87db38d47967eae159c5be17ab334bb6a4edffc;hp=5c50c6fb1fa4bb426bd5f537d9e769613911b59d;p=controller.git Merge "Fix bug 153: change the key container-config to ContainerConfig in the container manager module" --- diff --git a/opendaylight/arphandler/pom.xml b/opendaylight/arphandler/pom.xml index 8f1f4d5d2e..e3576e6ed8 100644 --- a/opendaylight/arphandler/pom.xml +++ b/opendaylight/arphandler/pom.xml @@ -14,7 +14,7 @@ HEAD arphandler - 0.4.1-SNAPSHOT + 0.5.1-SNAPSHOT bundle @@ -27,6 +27,7 @@ + org.opendaylight.controller.sal.packet.address, org.opendaylight.controller.connectionmanager, org.opendaylight.controller.sal.connection, org.opendaylight.controller.sal.core, @@ -72,7 +73,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java index abe104a406..8c91c71533 100644 --- a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java +++ b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -37,6 +36,8 @@ import org.opendaylight.controller.clustering.services.ICacheUpdateAware; import org.opendaylight.controller.clustering.services.IClusterContainerServices; import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.connectionmanager.IConnectionManager; +import org.opendaylight.controller.hosttracker.HostIdFactory; +import org.opendaylight.controller.hosttracker.IHostId; import org.opendaylight.controller.hosttracker.IfHostListener; import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; @@ -80,27 +81,29 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA private BlockingQueue ARPCacheEvents = new LinkedBlockingQueue(); private Thread cacheEventHandler; private boolean stopping = false; + /* * A cluster allocated cache. Used for synchronizing ARP request/reply - * events across all cluster controllers. To raise an event, we put() a specific - * event object (as key) and all nodes handle it in the entryUpdated callback. + * events across all cluster controllers. To raise an event, we put() a + * specific event object (as key) and all nodes handle it in the + * entryUpdated callback. * * In case of ARPReply, we put true value to send replies to any requestors * by calling generateAndSendReply */ private ConcurrentMap arpRequestReplyEvent; - void setConnectionManager(IConnectionManager cm){ + void setConnectionManager(IConnectionManager cm) { this.connectionManager = cm; } - void unsetConnectionManager(IConnectionManager cm){ - if (this.connectionManager == cm){ + void unsetConnectionManager(IConnectionManager cm) { + if (this.connectionManager == cm) { connectionManager = null; } } - void setClusterContainerService(IClusterContainerServices s){ + void setClusterContainerService(IClusterContainerServices s) { this.clusterContainerService = s; } @@ -164,11 +167,10 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } } - protected void sendARPReply(NodeConnector p, byte[] sMAC, InetAddress sIP, - byte[] tMAC, InetAddress tIP) { + protected void sendARPReply(NodeConnector p, byte[] sMAC, InetAddress sIP, byte[] tMAC, InetAddress tIP) { byte[] senderIP = sIP.getAddress(); byte[] targetIP = tIP.getAddress(); - ARP arp = createARP(ARP.REPLY,sMAC,senderIP,tMAC,targetIP); + ARP arp = createARP(ARP.REPLY, sMAC, senderIP, tMAC, targetIP); Ethernet ethernet = createEthernet(sMAC, tMAC, arp); @@ -214,8 +216,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA // Make sure that the host is a legitimate member of this subnet if (!subnet.hasNodeConnector(p)) { - log.debug("{} showing up on {} does not belong to {}", - new Object[] { sourceIP, p, subnet }); + log.debug("{} showing up on {} does not belong to {}", new Object[] { sourceIP, p, subnet }); return; } @@ -237,9 +238,9 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } /* - * OpCode != request -> ARP Reply. If there are hosts (in - * arpRequestors) waiting for the ARP reply for this sourceIP, it's - * time to generate the reply and send it to these hosts. + * OpCode != request -> ARP Reply. If there are hosts (in arpRequestors) + * waiting for the ARP reply for this sourceIP, it's time to generate + * the reply and send it to these hosts. * * If sourceIP==targetIP, it is a Gratuitous ARP. If there are hosts (in * arpRequestors) waiting for the ARP reply for this sourceIP, it's time @@ -247,27 +248,29 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA */ if (pkt.getOpCode() != ARP.REQUEST || sourceIP.equals(targetIP)) { - // Raise a reply event so that any waiting requestors will be sent a reply - // the true value indicates we should generate replies to requestors across the cluster + // Raise a reply event so that any waiting requestors will be sent a + // reply + // the true value indicates we should generate replies to requestors + // across the cluster log.trace("Received ARP reply packet from {}, reply to all requestors.", sourceIP); arpRequestReplyEvent.put(new ARPReply(sourceIP, sourceMAC), true); return; } /* - * ARP Request Handling: - * If targetIP is the IP of the subnet, reply with ARP REPLY - * If targetIP is a known host, PROXY ARP (by sending ARP REPLY) on behalf of known target hosts. - * For unknown target hosts, generate and send an ARP request to ALL switches/ports using - * the IP address defined in the subnet as source address + * ARP Request Handling: If targetIP is the IP of the subnet, reply with + * ARP REPLY If targetIP is a known host, PROXY ARP (by sending ARP + * REPLY) on behalf of known target hosts. For unknown target hosts, + * generate and send an ARP request to ALL switches/ports using the IP + * address defined in the subnet as source address */ /* * If target IP is gateway IP, Send ARP reply */ if ((targetIP.equals(subnet.getNetworkAddress())) && (NetUtils.isBroadcastMACAddr(targetMAC) || Arrays.equals(targetMAC, getControllerMAC()))) { - if (connectionManager.getLocalityStatus(p.getNode()) == ConnectionLocality.LOCAL){ - if (log.isTraceEnabled()){ + if (connectionManager.getLocalityStatus(p.getNode()) == ConnectionLocality.LOCAL) { + if (log.isTraceEnabled()) { log.trace("Received local ARP req. for default gateway. Replying with controller MAC: {}", HexEncode.bytesToHexString(getControllerMAC())); } @@ -280,8 +283,9 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA return; } - - HostNodeConnector host = hostTracker.hostQuery(targetIP); + // Hosttracker hosts db key implementation + IHostId id = HostIdFactory.create(targetIP, null); + HostNodeConnector host = hostTracker.hostQuery(id); // unknown host, initiate ARP request if (host == null) { // add the requestor to the list so that we can replay the reply @@ -293,48 +297,40 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA arpRequestors.put(targetIP, requestorSet); } requestorSet.add(requestor); - countDownTimers.put(targetIP, (short) 2); // reset timeout to 2sec + countDownTimers.put(targetIP, (short) 2); // reset timeout to + // 2sec } - //Raise a bcast request event, all controllers need to send one + // Raise a bcast request event, all controllers need to send one log.trace("Sending a bcast ARP request for {}", targetIP); arpRequestReplyEvent.put(new ARPRequest(targetIP, subnet), false); } else { /* - * Target host known (across the cluster), send ARP REPLY make sure that targetMAC - * matches the host's MAC if it is not broadcastMAC + * Target host known (across the cluster), send ARP REPLY make sure + * that targetMAC matches the host's MAC if it is not broadcastMAC */ if (NetUtils.isBroadcastMACAddr(targetMAC) || Arrays.equals(host.getDataLayerAddressBytes(), targetMAC)) { log.trace("Received ARP req. for known host {}, sending reply...", targetIP); if (connectionManager.getLocalityStatus(p.getNode()) == ConnectionLocality.LOCAL) { - sendARPReply(p, - host.getDataLayerAddressBytes(), - host.getNetworkAddress(), - pkt.getSenderHardwareAddress(), - sourceIP); + sendARPReply(p, host.getDataLayerAddressBytes(), host.getNetworkAddress(), + pkt.getSenderHardwareAddress(), sourceIP); } else { - arpRequestReplyEvent.put(new ARPReply( - p, - host.getNetworkAddress(), - host.getDataLayerAddressBytes(), - sourceIP, - pkt.getSenderHardwareAddress()), false); + arpRequestReplyEvent.put(new ARPReply(p, host.getNetworkAddress(), host.getDataLayerAddressBytes(), + sourceIP, pkt.getSenderHardwareAddress()), false); } } else { /* - * Target MAC has been changed. For now, discard it. - * TODO: We may need to send unicast ARP REQUEST on behalf of - * the target back to the sender to trigger the sender to update - * its table + * Target MAC has been changed. For now, discard it. TODO: We + * may need to send unicast ARP REQUEST on behalf of the target + * back to the sender to trigger the sender to update its table */ } } } /** - * Send a broadcast ARP Request to the switch/ ports using - * the networkAddress of the subnet as sender IP - * the controller's MAC as sender MAC - * the targetIP as the target Network Address + * Send a broadcast ARP Request to the switch/ ports using the + * networkAddress of the subnet as sender IP the controller's MAC as sender + * MAC the targetIP as the target Network Address */ protected void sendBcastARPRequest(InetAddress targetIP, Subnet subnet) { log.trace("sendBcatARPRequest targetIP:{} subnet:{}", targetIP, subnet); @@ -349,10 +345,11 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } byte[] targetHardwareAddress = new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 }; - //TODO: should use IBroadcastHandler instead + // TODO: should use IBroadcastHandler instead for (NodeConnector p : nodeConnectors) { - //filter out any non-local or internal ports - if (!(connectionManager.getLocalityStatus(p.getNode()) == ConnectionLocality.LOCAL) || topologyManager.isInternal(p)) { + // filter out any non-local or internal ports + if (!(connectionManager.getLocalityStatus(p.getNode()) == ConnectionLocality.LOCAL) + || topologyManager.isInternal(p)) { continue; } log.trace("Sending toward nodeConnector:{}", p); @@ -374,8 +371,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA /** * Send a unicast ARP Request to the known host on a specific switch/port as - * defined in the host. - * The sender IP is the networkAddress of the subnet + * defined in the host. The sender IP is the networkAddress of the subnet * The sender MAC is the controller's MAC */ protected void sendUcastARPRequest(HostNodeConnector host, Subnet subnet) { @@ -425,15 +421,14 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA Subnet subnet = null; if (switchManager != null) { - subnet = switchManager.getSubnetByNetworkAddress(host - .getNetworkAddress()); + subnet = switchManager.getSubnetByNetworkAddress(host.getNetworkAddress()); } if (subnet == null) { log.debug("can't find subnet matching {}", host.getNetworkAddress()); return; } - if (connectionManager.getLocalityStatus(host.getnodeconnectorNode()) == ConnectionLocality.LOCAL){ + if (connectionManager.getLocalityStatus(host.getnodeconnectorNode()) == ConnectionLocality.LOCAL) { log.trace("Send a ucast ARP req. to: {}", host); sendUcastARPRequest(host, subnet); } else { @@ -443,9 +438,9 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } /** - * An IP packet is punted to the controller, this means that the - * destination host is not known to the controller. - * Need to discover it by sending a Broadcast ARP Request + * An IP packet is punted to the controller, this means that the destination + * host is not known to the controller. Need to discover it by sending a + * Broadcast ARP Request * * @param pkt * @param p @@ -454,7 +449,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA InetAddress dIP = NetUtils.getInetAddress(pkt.getDestinationAddress()); if (dIP == null) { - return; + return; } // try to find a matching subnet @@ -468,20 +463,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } // see if we know about the host - HostNodeConnector host = hostTracker.hostFind(dIP); + // Hosttracker hosts db key implementation + IHostId id = HostIdFactory.create(dIP, null); + HostNodeConnector host = hostTracker.hostFind(id); if (host == null) { // if we don't, know about the host, try to find it - log.trace("Punted IP pkt to {}, sending bcast ARP event...", - dIP); + log.trace("Punted IP pkt to {}, sending bcast ARP event...", dIP); /* * unknown destination host, initiate bcast ARP request */ arpRequestReplyEvent.put(new ARPRequest(dIP, subnet), false); - } else if (routing == null || - routing.getRoute(p.getNode(), host.getnodeconnectorNode()) != null) { - /* if IRouting is available, make sure that this packet can get it's + } else if (routing == null || routing.getRoute(p.getNode(), host.getnodeconnectorNode()) != null) { + /* + * if IRouting is available, make sure that this packet can get it's * destination normally before teleporting it there. If it's not * available, then assume it's reachable. * @@ -490,9 +486,11 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA log.trace("forwarding punted IP pkt to {} received at {}", dIP, p); - /* if we know where the host is and there's a path from where this + /* + * if we know where the host is and there's a path from where this * packet was punted to where the host is, then deliver it to the - * host for now */ + * host for now + */ NodeConnector nc = host.getnodeConnector(); // re-encode the Ethernet packet (the parent of the IPv4 packet) @@ -500,8 +498,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA rp.setOutgoingNodeConnector(nc); this.dataPacketService.transmitDataPacket(rp); } else { - log.trace("ignoring punted IP pkt to {} because there is no route from {}", - dIP, p); + log.trace("ignoring punted IP pkt to {} because there is no route from {}", dIP, p); } } @@ -524,19 +521,20 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA allocateCaches(); retrieveCaches(); + } @SuppressWarnings({ "unchecked" }) private void retrieveCaches() { - ConcurrentMap map; + ConcurrentMap map; - if (this.clusterContainerService == null){ + if (this.clusterContainerService == null) { log.error("Cluster service unavailable, can't retieve ARPHandler caches!"); return; } map = clusterContainerService.getCache(ARP_EVENT_CACHE_NAME); - if (map != null){ + if (map != null) { this.arpRequestReplyEvent = (ConcurrentMap) map; } else { log.error("Cache allocation failed for {}", ARP_EVENT_CACHE_NAME); @@ -544,30 +542,31 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } private void allocateCaches() { - if (clusterContainerService == null){ + if (clusterContainerService == null) { nonClusterObjectCreate(); log.error("Clustering service unavailable. Allocated non-cluster caches for ARPHandler."); return; } - try{ + try { clusterContainerService.createCache(ARP_EVENT_CACHE_NAME, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - } catch (CacheConfigException e){ + } catch (CacheConfigException e) { log.error("ARPHandler cache configuration invalid!"); - } catch (CacheExistException e){ + } catch (CacheExistException e) { log.debug("ARPHandler cache exists, skipped allocation."); } } - private void nonClusterObjectCreate(){ + private void nonClusterObjectCreate() { arpRequestReplyEvent = new ConcurrentHashMap(); } + /** - * Function called by the dependency manager when at least one - * dependency become unsatisfied or when the component is shutting - * down because for example bundle is being stopped. + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. * */ void destroy() { @@ -575,9 +574,8 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } /** - * Function called by dependency manager after "init ()" is called - * and after the services provided by the class are registered in - * the service registry + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry * */ void start() { @@ -587,12 +585,12 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls * */ - void stop(){ + void stop() { } void stopping() { @@ -626,25 +624,25 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA handlePuntedIPPacket((IPv4) nextPak, inPkt.getIncomingNodeConnector()); } else if (nextPak instanceof ARP) { log.trace("Handle ARP packet: {}", formattedPak); - handleARPPacket((Ethernet) formattedPak, (ARP) nextPak, inPkt - .getIncomingNodeConnector()); + handleARPPacket((Ethernet) formattedPak, (ARP) nextPak, inPkt.getIncomingNodeConnector()); } } return PacketResult.IGNORED; } - private ARP createARP(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress, byte[] targetIP) { - ARP arp = new ARP(); - arp.setHardwareType(ARP.HW_TYPE_ETHERNET); - arp.setProtocolType(EtherTypes.IPv4.shortValue()); - arp.setHardwareAddressLength((byte) 6); - arp.setProtocolAddressLength((byte) 4); - arp.setOpCode(opCode); - arp.setSenderHardwareAddress(senderMacAddress) ; - arp.setSenderProtocolAddress(senderIP); - arp.setTargetHardwareAddress(targetMacAddress); - arp.setTargetProtocolAddress(targetIP); - return arp; + private ARP createARP(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress, + byte[] targetIP) { + ARP arp = new ARP(); + arp.setHardwareType(ARP.HW_TYPE_ETHERNET); + arp.setProtocolType(EtherTypes.IPv4.shortValue()); + arp.setHardwareAddressLength((byte) 6); + arp.setProtocolAddressLength((byte) 4); + arp.setOpCode(opCode); + arp.setSenderHardwareAddress(senderMacAddress); + arp.setSenderProtocolAddress(senderIP); + arp.setTargetHardwareAddress(targetMacAddress); + arp.setTargetProtocolAddress(targetIP); + return arp; } private Ethernet createEthernet(byte[] sourceMAC, byte[] targetMAC, ARP arp) { @@ -682,10 +680,10 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA // Clean up ARP event cache try { - if (clusterContainerService.amICoordinator() && ! arpRequestReplyEvent.isEmpty()){ + if (clusterContainerService.amICoordinator() && !arpRequestReplyEvent.isEmpty()) { arpRequestReplyEvent.clear(); } - } catch (Exception e){ + } catch (Exception e) { log.warn("ARPHandler: A cluster member failed to clear event cache."); } } @@ -701,7 +699,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA private void generateAndSendReply(InetAddress sourceIP, byte[] sourceMAC) { if (log.isTraceEnabled()) { log.trace("generateAndSendReply called with params sourceIP:{} sourceMAC:{}", sourceIP, - HexEncode.bytesToHexString(sourceMAC)); + HexEncode.bytesToHexString(sourceMAC)); } Set hosts = arpRequestors.remove(sourceIP); if ((hosts == null) || hosts.isEmpty()) { @@ -711,38 +709,27 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA countDownTimers.remove(sourceIP); for (HostNodeConnector host : hosts) { if (log.isTraceEnabled()) { - log.trace("Sending ARP Reply with src {}/{}, target {}/{}", - new Object[] { - HexEncode.bytesToHexString(sourceMAC), - sourceIP, - HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), - host.getNetworkAddress() }); + log.trace( + "Sending ARP Reply with src {}/{}, target {}/{}", + new Object[] { HexEncode.bytesToHexString(sourceMAC), sourceIP, + HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host.getNetworkAddress() }); } - if (connectionManager.getLocalityStatus(host.getnodeconnectorNode()) == ConnectionLocality.LOCAL){ - sendARPReply(host.getnodeConnector(), - sourceMAC, - sourceIP, - host.getDataLayerAddressBytes(), + if (connectionManager.getLocalityStatus(host.getnodeconnectorNode()) == ConnectionLocality.LOCAL) { + sendARPReply(host.getnodeConnector(), sourceMAC, sourceIP, host.getDataLayerAddressBytes(), host.getNetworkAddress()); } else { /* - * In the remote event a requestor moved to another - * controller it may turn out it now we need to send - * the ARP reply from a different controller, this - * cover the case + * In the remote event a requestor moved to another controller + * it may turn out it now we need to send the ARP reply from a + * different controller, this cover the case */ arpRequestReplyEvent.put( - new ARPReply( - host.getnodeConnector(), - sourceIP, - sourceMAC, - host.getNetworkAddress(), - host.getDataLayerAddressBytes()), false); + new ARPReply(host.getnodeConnector(), sourceIP, sourceMAC, host.getNetworkAddress(), host + .getDataLayerAddressBytes()), false); } } } - @Override public void entryUpdated(ARPEvent key, Boolean new_value, String cacheName, boolean originLocal) { log.trace("Got and entryUpdated for cacheName {} key {} isNew {}", cacheName, key, new_value); @@ -753,12 +740,13 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA public void entryCreated(ARPEvent key, String cacheName, boolean originLocal) { // nothing to do } + @Override public void entryDeleted(ARPEvent key, String cacheName, boolean originLocal) { // nothing to do } - private void enqueueARPCacheEvent (ARPEvent event, boolean new_value) { + private void enqueueARPCacheEvent(ARPEvent event, boolean new_value) { try { ARPCacheEvent cacheEvent = new ARPCacheEvent(event, new_value); if (!ARPCacheEvents.contains(cacheEvent)) { @@ -771,7 +759,8 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } /* - * this thread monitors the connectionEvent queue for new incoming events from + * this thread monitors the connectionEvent queue for new incoming events + * from */ private class ARPCacheEventHandler implements Runnable { @Override @@ -787,24 +776,22 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA log.trace("Trigger and ARP Broadcast Request upon receipt of {}", req); sendBcastARPRequest(req.getTargetIP(), req.getSubnet()); - //If unicast and local, send reply + // If unicast and local, send reply } else if (connectionManager.getLocalityStatus(req.getHost().getnodeconnectorNode()) == ConnectionLocality.LOCAL) { log.trace("ARPCacheEventHandler - sendUcatARPRequest upon receipt of {}", req); sendUcastARPRequest(req.getHost(), req.getSubnet()); } } else if (event instanceof ARPReply) { ARPReply rep = (ARPReply) event; - // New reply received by controller, notify all awaiting requestors across the cluster + // New reply received by controller, notify all awaiting + // requestors across the cluster if (ev.isNewReply()) { log.trace("Trigger a generateAndSendReply in response to {}", rep); generateAndSendReply(rep.getTargetIP(), rep.getTargetMac()); - // Otherwise, a specific reply. If local, send out. + // Otherwise, a specific reply. If local, send out. } else if (connectionManager.getLocalityStatus(rep.getPort().getNode()) == ConnectionLocality.LOCAL) { log.trace("ARPCacheEventHandler - sendUcatARPReply locally in response to {}", rep); - sendARPReply(rep.getPort(), - rep.getSourceMac(), - rep.getSourceIP(), - rep.getTargetMac(), + sendARPReply(rep.getPort(), rep.getSourceMac(), rep.getSourceIP(), rep.getTargetMac(), rep.getTargetIP()); } } diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 8feb1600b5..794986a7bb 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -76,6 +76,10 @@ 0.6.0-SNAPSHOT 0.4.1-SNAPSHOT + 0.5.1-SNAPSHOT + 0.5.1-SNAPSHOT + 0.5.1-SNAPSHOT + 0.5.1-SNAPSHOT 0.2.3-SNAPSHOT 0.2.3-SNAPSHOT 1.0-SNAPSHOT diff --git a/opendaylight/config/config-api/src/main/resources/META-INF/yang/config.yang b/opendaylight/config/config-api/src/main/resources/META-INF/yang/config.yang index 5d6c11fbee..a0a4292adf 100644 --- a/opendaylight/config/config-api/src/main/resources/META-INF/yang/config.yang +++ b/opendaylight/config/config-api/src/main/resources/META-INF/yang/config.yang @@ -122,9 +122,7 @@ module config { the actual service-type which is actually required."; mandatory true; - type leafref { - path "/config:services/config:service/config:type"; - } + type service-type-ref; } leaf name { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java index f93409f99e..84c2c6dd4d 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java @@ -275,6 +275,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe ModuleJMXRegistrator newModuleJMXRegistrator = baseJMXRegistrator .createModuleJMXRegistrator(); + OsgiRegistration osgiRegistration = null; if (entry.hasOldModule()) { ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo(); DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo @@ -282,19 +283,21 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe currentConfig.remove(entry.getName()); // test if old instance == new instance - if (oldReadableConfigBean.getInstance().equals( - module.getInstance())) { + if (oldReadableConfigBean.getInstance().equals(module.getInstance())) { // reused old instance: // wrap in readable dynamic mbean reusedInstances.add(primaryReadOnlyON); + osgiRegistration = oldInternalInfo.getOsgiRegistration(); } else { // recreated instance: // it is responsibility of module to call the old instance - // we just need to unregister configbean recreatedInstances.add(primaryReadOnlyON); + + // close old osgi registration + oldInternalInfo.getOsgiRegistration().close(); } - // close old osgi registration in any case - oldInternalInfo.getOsgiRegistration().close(); + // close old module jmx registrator oldInternalInfo.getModuleJMXRegistrator().close(); } else { @@ -316,10 +319,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe } // register to OSGi - OsgiRegistration osgiRegistration = beanToOsgiServiceManager - .registerToOsgi(module.getClass(), - newReadableConfigBean.getInstance(), - entry.getName()); + if (osgiRegistration == null) { + osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(), + newReadableConfigBean.getInstance(), entry.getName()); + } RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = runtimeRegistrators .get(entry.getName()); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java index e71aef4c04..c4f40fbeeb 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java @@ -36,6 +36,11 @@ public class ModuleInternalTransactionalInfo implements Identifiable loggersDTOs; private Map rollingDTOs; private Map consoleDTOs; private Map fileDTOs; @Override - public LogbackModule instantiateModule(String instanceName, - DependencyResolver dependencyResolver, BundleContext bundleContext) { + public LogbackModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, + BundleContext bundleContext) { Preconditions.checkArgument(instanceName.equals(INSTANCE_NAME), "There should be just one instance of logback, named " + INSTANCE_NAME); prepareDTOs(); @@ -61,9 +66,8 @@ public class LogbackModuleFactory extends } @Override - public LogbackModule instantiateModule(String instanceName, - DependencyResolver dependencyResolver, LogbackModule oldModule, - AutoCloseable oldInstance, BundleContext bundleContext) { + public LogbackModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, + LogbackModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) { Preconditions.checkArgument(instanceName.equals(INSTANCE_NAME), "There should be just one instance of logback, named " + INSTANCE_NAME); prepareDTOs(); @@ -220,4 +224,14 @@ public class LogbackModuleFactory extends return Lists.newArrayList(loggersToReturn.values()); } + @Override + public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, + BundleContext bundleContext) { + DependencyResolver resolver = dependencyResolverFactory.createDependencyResolver(new ModuleIdentifier( + getImplementationName(), INSTANCE_NAME)); + LogbackModule defaultLogback = instantiateModule(INSTANCE_NAME, resolver, bundleContext); + Set defaultModules = Sets.newHashSet(defaultLogback); + return defaultModules; + } + } diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java index 846b9cd352..296ce79f6e 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java @@ -7,29 +7,24 @@ */ package org.opendaylight.controller.config.yang.logback.config; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; +import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + public class LogbackModuleTest extends AbstractConfigTest { private static final String INSTANCE_NAME = "singleton"; @@ -37,14 +32,14 @@ public class LogbackModuleTest extends AbstractConfigTest { private LogbackModuleFactory factory; @Before - public void setUp() throws IOException, ClassNotFoundException, InterruptedException { + public void setUp() throws Exception { factory = new LogbackModuleFactory(); super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory)); } @Test - public void testCreateBean() throws InstanceAlreadyExistsException { + public void testCreateBean() throws Exception { CommitStatus status = createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", @@ -55,7 +50,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testReusingInstance() throws InstanceAlreadyExistsException { + public void testReusingInstance() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -70,8 +65,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testRecreateInstance() throws InstanceAlreadyExistsException, ValidationException, - ConflictingVersionException, InstanceNotFoundException { + public void testRecreateInstance() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -88,7 +82,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testDestroyInstance() throws InstanceNotFoundException, InstanceAlreadyExistsException { + public void testDestroyInstance() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -104,7 +98,7 @@ public class LogbackModuleTest extends AbstractConfigTest { @Ignore @Test - public void testValidation1() throws InstanceAlreadyExistsException { + public void testValidation1() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", @@ -116,7 +110,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation2() throws InstanceAlreadyExistsException { + public void testValidation2() throws Exception { try { createBeans(true, "target/rollingApp", null, "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender").commit(); @@ -127,7 +121,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation4() throws InstanceAlreadyExistsException { + public void testValidation4() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", null, 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", @@ -139,7 +133,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation6() throws InstanceAlreadyExistsException { + public void testValidation6() throws Exception { try { createBeans(true, "", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "FixedWindowRollingPolicy", 0, "FileAppender") @@ -151,7 +145,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation7() throws InstanceAlreadyExistsException { + public void testValidation7() throws Exception { try { createBeans( @@ -164,7 +158,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation8() throws InstanceAlreadyExistsException { + public void testValidation8() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", null, "DEBUG", "FixedWindowRollingPolicy", 0, @@ -176,7 +170,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation9() throws InstanceAlreadyExistsException { + public void testValidation9() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, 5, "target/%i.log", "rolling", "consoleName", "ALL", "", "DEBUG", "FixedWindowRollingPolicy", 0, @@ -188,7 +182,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation10() throws InstanceAlreadyExistsException { + public void testValidation10() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", null, 5, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", @@ -200,7 +194,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation11() throws InstanceAlreadyExistsException { + public void testValidation11() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", @@ -212,7 +206,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation12() throws InstanceAlreadyExistsException { + public void testValidation12() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", null, 1, "FileAppender") @@ -224,7 +218,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation13() throws InstanceAlreadyExistsException { + public void testValidation13() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "", 1, "FileAppender") @@ -236,7 +230,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testValidation14() throws InstanceAlreadyExistsException { + public void testValidation14() throws Exception { try { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", 1, null, "target/%i.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "RollingPolicy", 1, @@ -248,7 +242,7 @@ public class LogbackModuleTest extends AbstractConfigTest { } @Test - public void testTimeBasedRollingPolicy() throws InstanceAlreadyExistsException { + public void testTimeBasedRollingPolicy() throws Exception { createBeans(true, "target/rollingApp", "%-4relative [%thread] %-5level %logger{35} - %msg%n", "30MB", null, null, "target/%d.log", "rolling", "consoleName", "ALL", "logger1", "DEBUG", "TimeBasedRollingPolicy", 1, "FileAppender").commit(); @@ -257,10 +251,10 @@ public class LogbackModuleTest extends AbstractConfigTest { private ConfigTransactionJMXClient createBeans(Boolean isAppend, String rollingFileName, String encoderPattern, String maxFileSize, Integer minIndex, Integer maxIndex, String fileNamePattern, String rollingName, String consoleName, String thresholdFilter, String loggerName, String level, String rollingPolicyType, - int maxHistory, String fileAppName) throws InstanceAlreadyExistsException { + int maxHistory, String fileAppName) throws Exception { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), INSTANCE_NAME); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), INSTANCE_NAME); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); List rollingAppenders = new ArrayList<>(); RollingFileAppenderTO rollingAppender = new RollingFileAppenderTO(); diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java index 79e46ae6d2..eeb8289e86 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java @@ -17,7 +17,9 @@ import java.util.Arrays; import java.util.List; import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; import javax.management.JMX; +import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.io.FileUtils; @@ -142,7 +144,8 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes } - public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException { + public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException, + MalformedObjectNameException, InstanceNotFoundException { LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); @@ -200,8 +203,8 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes loggersDTOs.add(log); ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), "singleton"); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); bean.setLoggerTO(loggersDTOs); bean.setRollingFileAppenderTO(rollingAppenders); @@ -210,6 +213,6 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes transaction.commit(); - return nameCreated; + return nameRetrieved; } } diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java index 004c18c5e0..8718f8a9ce 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java @@ -17,6 +17,7 @@ import java.util.List; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.JMX; +import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.io.FileUtils; @@ -27,12 +28,12 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; import org.slf4j.LoggerFactory; -import com.google.common.collect.Lists; - import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; +import com.google.common.collect.Lists; + public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { private LogbackModuleFactory factory; @@ -56,14 +57,16 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { /** * Tests configuration of Logger factory. + * + * @throws MalformedObjectNameException */ @Test - public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException { + public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), "singleton"); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); assertEquals(1, bean.getConsoleAppenderTO().size()); @@ -73,9 +76,9 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { transaction = configRegistryClient.createTransaction(); - nameCreated = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); + nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); - bean = JMX.newMXBeanProxy(platformMBeanServer, nameCreated, LogbackModuleMXBean.class); + bean = JMX.newMXBeanProxy(platformMBeanServer, nameRetrieved, LogbackModuleMXBean.class); assertEquals(1, bean.getConsoleAppenderTO().size()); assertEquals(1, bean.getRollingFileAppenderTO().size()); @@ -89,11 +92,6 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { @Test public void testAllLoggers() throws InstanceAlreadyExistsException, InstanceNotFoundException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - transaction.createModule(factory.getImplementationName(), "singleton"); - - transaction.commit(); - - transaction = configRegistryClient.createTransaction(); LogbackModuleMXBean bean = JMX.newMXBeanProxy(ManagementFactory.getPlatformMBeanServer(), transaction.lookupConfigBean("logback", "singleton"), LogbackModuleMXBean.class); @@ -103,13 +101,16 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { /** * Add new logger using FileAppender + * + * @throws MalformedObjectNameException */ @Test - public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException { + public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException, + MalformedObjectNameException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), "singleton"); - LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameCreated, LogbackModuleMXBean.class); + ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); + LogbackModuleMXBean bean = transaction.newMXBeanProxy(nameRetrieved, LogbackModuleMXBean.class); assertEquals(5, bean.getLoggerTO().size()); @@ -124,8 +125,8 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { transaction.commit(); transaction = configRegistryClient.createTransaction(); - nameCreated = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); - bean = JMX.newMXBeanProxy(platformMBeanServer, nameCreated, LogbackModuleMXBean.class); + nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), "singleton"); + bean = JMX.newMXBeanProxy(platformMBeanServer, nameRetrieved, LogbackModuleMXBean.class); assertEquals(6, bean.getLoggerTO().size()); } diff --git a/opendaylight/config/netty-config-api/pom.xml b/opendaylight/config/netty-config-api/pom.xml new file mode 100644 index 0000000000..9a2fe37258 --- /dev/null +++ b/opendaylight/config/netty-config-api/pom.xml @@ -0,0 +1,54 @@ + + + org.opendaylight.controller + config-subsystem + 0.2.3-SNAPSHOT + + 4.0.0 + netty-config-api + ${project.artifactId} + bundle + + 3.0.4 + + + + + org.opendaylight.controller + config-api + + + com.google.guava + guava + + + io.netty + netty-transport + + + + + + org.apache.felix + maven-bundle-plugin + + + + org.opendaylight.controller.config.api.*, + io.netty.channel, + io.netty.util, + io.netty.util.concurrent + + + org.opendaylight.controller.config.yang.netty + + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + \ No newline at end of file diff --git a/opendaylight/config/netty-config-api/src/main/yang/netty.yang b/opendaylight/config/netty-config-api/src/main/yang/netty.yang new file mode 100644 index 0000000000..7f7a3ff4ce --- /dev/null +++ b/opendaylight/config/netty-config-api/src/main/yang/netty.yang @@ -0,0 +1,52 @@ +// vi: set smarttab et sw=4 tabstop=4: +module netty { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:netty"; + prefix "netty"; + + import config { prefix config; revision-date 2013-04-05; } + + organization "Cisco Systems, Inc."; + + contact "Milos Fabian "; + + description + "This module contains the base YANG definitions for + netty services. + + Copyright (c)2013 Cisco Systems, Inc. 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"; + + revision "2013-11-19" { + description + "Initial revision."; + } + + identity netty-threadgroup { + description + "Configuration wrapper around netty's threadgroup"; + + base "config:service-type"; + config:java-class "io.netty.channel.EventLoopGroup"; + } + + identity netty-event-executor { + description + "Configuration wrapper around netty's event executor"; + + base "config:service-type"; + config:java-class "io.netty.util.concurrent.EventExecutor"; + } + + identity netty-timer { + description + "Configuration wrapper around netty's timer"; + + base "config:service-type"; + config:java-class "io.netty.util.Timer"; + } +} \ No newline at end of file diff --git a/opendaylight/config/netty-event-executor-config/pom.xml b/opendaylight/config/netty-event-executor-config/pom.xml index a2ce94f340..3d5384d171 100644 --- a/opendaylight/config/netty-event-executor-config/pom.xml +++ b/opendaylight/config/netty-event-executor-config/pom.xml @@ -21,17 +21,13 @@ org.opendaylight.controller - threadpool-config-api + netty-config-api ${project.version} org.slf4j slf4j-api - - com.google.guava - guava - @@ -80,7 +76,7 @@ com.google.common.base, - org.opendaylight.controller.config.yang.threadpool, + org.opendaylight.controller.config.yang.netty, io.netty.util.concurrent, org.opendaylight.controller.config.api, org.opendaylight.controller.config.api.annotations, diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java index 3707f016a2..aed3a0cc15 100644 --- a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java +++ b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java @@ -37,7 +37,6 @@ public final class GlobalEventExecutorModule extends @Override public void validate() { super.validate(); - // Add custom validation for module attributes here. } @Override diff --git a/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang b/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang index d45eccded8..16e5c07356 100644 --- a/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang +++ b/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang @@ -2,18 +2,18 @@ module netty-event-executor { yang-version 1; namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor"; - prefix "netty-t"; + prefix "netty-ee"; import config { prefix config; revision-date 2013-04-05; } - import threadpool { prefix th; revision-date 2013-04-09; } + import netty { prefix netty; revision-date 2013-11-19; } organization "Cisco Systems, Inc."; contact "Milos Fabian "; description - "This module contains the base YANG definitions for NS-OS - thread-related services. + "This module contains the base YANG definitions for + netty event executor implementation. Copyright (c)2013 Cisco Systems, Inc. All rights reserved.; @@ -29,7 +29,7 @@ module netty-event-executor { identity netty-global-event-executor { base config:module-type; - config:provided-service th:netty-event-executor; + config:provided-service netty:netty-event-executor; config:java-name-prefix GlobalEventExecutor; } @@ -39,6 +39,4 @@ module netty-event-executor { } } - - } diff --git a/opendaylight/config/netty-threadgroup-config/pom.xml b/opendaylight/config/netty-threadgroup-config/pom.xml index ef63fce2ce..8dc989e728 100644 --- a/opendaylight/config/netty-threadgroup-config/pom.xml +++ b/opendaylight/config/netty-threadgroup-config/pom.xml @@ -25,21 +25,14 @@ org.opendaylight.controller - threadpool-config-api + netty-config-api ${project.version} - org.slf4j slf4j-api - - - com.google.guava - guava - - junit @@ -82,7 +75,6 @@ org.apache.felix maven-bundle-plugin - 2.3.7 true @@ -92,7 +84,7 @@ com.google.common.base, io.netty.channel.nio, - org.opendaylight.controller.config.yang.threadpool, + org.opendaylight.controller.config.yang.netty, io.netty.util.concurrent, org.opendaylight.controller.config.api, org.opendaylight.controller.config.api.annotations, diff --git a/opendaylight/config/netty-threadgroup-config/src/main/java/org/opendaylight/controller/config/yang/netty/threadgroup/NettyThreadgroupModule.java b/opendaylight/config/netty-threadgroup-config/src/main/java/org/opendaylight/controller/config/yang/netty/threadgroup/NettyThreadgroupModule.java index fd6b216f53..9ceef3116a 100644 --- a/opendaylight/config/netty-threadgroup-config/src/main/java/org/opendaylight/controller/config/yang/netty/threadgroup/NettyThreadgroupModule.java +++ b/opendaylight/config/netty-threadgroup-config/src/main/java/org/opendaylight/controller/config/yang/netty/threadgroup/NettyThreadgroupModule.java @@ -9,9 +9,10 @@ */ package org.opendaylight.controller.config.yang.netty.threadgroup; -import com.google.common.base.Preconditions; import io.netty.channel.nio.NioEventLoopGroup; +import org.opendaylight.controller.config.api.JmxAttributeValidationException; + /** * */ @@ -28,7 +29,8 @@ public final class NettyThreadgroupModule extends org.opendaylight.controller.co @Override public void validate(){ if(getThreadCount()!=null) { - Preconditions.checkArgument(getThreadCount() > 0, "Thread count cannot be < 0"); + JmxAttributeValidationException.checkCondition(getThreadCount() > 0, "value must be greater than 0", + threadCountJmxAttribute); } } diff --git a/opendaylight/config/netty-threadgroup-config/src/main/yang/nsos-netty-threadgroup.yang b/opendaylight/config/netty-threadgroup-config/src/main/yang/netty-threadgroup.yang similarity index 83% rename from opendaylight/config/netty-threadgroup-config/src/main/yang/nsos-netty-threadgroup.yang rename to opendaylight/config/netty-threadgroup-config/src/main/yang/netty-threadgroup.yang index f13cf391bf..e648c5328a 100644 --- a/opendaylight/config/netty-threadgroup-config/src/main/yang/nsos-netty-threadgroup.yang +++ b/opendaylight/config/netty-threadgroup-config/src/main/yang/netty-threadgroup.yang @@ -1,19 +1,19 @@ // vi: set smarttab et sw=4 tabstop=4: -module nsos-threadpool { +module threadgroup { yang-version 1; namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup"; - prefix "netty-t"; + prefix "netty-th"; import config { prefix config; revision-date 2013-04-05; } - import threadpool { prefix th; revision-date 2013-04-09; } + import netty { prefix netty; revision-date 2013-11-19; } organization "Cisco Systems, Inc."; contact "Robert Varga "; description - "This module contains the base YANG definitions for NS-OS - thread-related services. + "This module contains the base YANG definitions for + netty threadgroup implementation. Copyright (c)2013 Cisco Systems, Inc. All rights reserved."; @@ -24,7 +24,7 @@ module nsos-threadpool { identity netty-threadgroup-fixed { base config:module-type; - config:provided-service th:netty-threadgroup; + config:provided-service netty:netty-threadgroup; config:java-name-prefix NettyThreadgroup; } diff --git a/opendaylight/config/netty-timer-config/pom.xml b/opendaylight/config/netty-timer-config/pom.xml new file mode 100644 index 0000000000..095e71fcf5 --- /dev/null +++ b/opendaylight/config/netty-timer-config/pom.xml @@ -0,0 +1,114 @@ + + + org.opendaylight.controller + config-subsystem + 0.2.3-SNAPSHOT + + 4.0.0 + netty-timer-config + Configuration Wrapper around netty's timer + bundle + ${project.artifactId} + + 3.0.4 + + + + + org.opendaylight.controller + config-api + + + org.opendaylight.controller + netty-config-api + ${project.version} + + + org.opendaylight.controller + threadpool-config-api + ${project.version} + + + org.slf4j + slf4j-api + + + + + junit + junit + test + + + org.opendaylight.controller + config-manager + test + test-jar + + + org.opendaylight.controller + config-manager + test + + + org.opendaylight.controller + config-util + test + + + org.opendaylight.bgpcep + mockito-configuration + test + + + org.opendaylight.controller + threadpool-config-impl + ${project.version} + test + + + + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + + + + javax.management, + com.google.common.base, + org.opendaylight.controller.config.yang.netty, + org.opendaylight.controller.config.yang.threadpool, + io.netty.util, + org.opendaylight.controller.config.api, + org.opendaylight.controller.config.api.annotations, + org.opendaylight.controller.config.api.runtime, + org.opendaylight.controller.config.spi, + org.slf4j, + org.osgi.framework + + + + + + + + + + ${project.artifactId} + NETTY-TIMER-CONFIG Module site + ${basedir}/target/site/${project.artifactId} + + + \ No newline at end of file diff --git a/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModule.java b/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModule.java new file mode 100644 index 0000000000..cc78124680 --- /dev/null +++ b/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModule.java @@ -0,0 +1,99 @@ +/** + * Generated file + + * Generated from: yang module name: netty-event-executor yang module local name: netty-hashed-wheel-timer + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Tue Nov 19 12:49:59 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.netty.timer; + +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.config.api.JmxAttributeValidationException; + +/** +* +*/ +public final class HashedWheelTimerModule extends + org.opendaylight.controller.config.yang.netty.timer.AbstractHashedWheelTimerModule { + + public HashedWheelTimerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public HashedWheelTimerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + HashedWheelTimerModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + if (getTickDuration() != null) { + JmxAttributeValidationException.checkCondition(getTickDuration() > 0, "value must be greater than 0", + tickDurationJmxAttribute); + } + if (getTicksPerWheel() != null) { + JmxAttributeValidationException.checkCondition(getTicksPerWheel() > 0, "value must be greater than 0", + ticksPerWheelJmxAttribute); + } + } + + @Override + public java.lang.AutoCloseable createInstance() { + TimeUnit unit = TimeUnit.MILLISECONDS; + if (getTickDuration() != null && getThreadFactoryDependency() == null && getTicksPerWheel() == null) { + return new HashedWheelTimerCloseable(new HashedWheelTimer(getTickDuration(), unit)); + } + if (getTickDuration() != null && getThreadFactoryDependency() == null && getTicksPerWheel() != null) { + return new HashedWheelTimerCloseable(new HashedWheelTimer(getTickDuration(), unit, getTicksPerWheel())); + } + if (getTickDuration() == null && getThreadFactoryDependency() != null && getTicksPerWheel() == null) { + return new HashedWheelTimerCloseable(new HashedWheelTimer(getThreadFactoryDependency())); + } + if (getTickDuration() != null && getThreadFactoryDependency() != null && getTicksPerWheel() == null) { + return new HashedWheelTimerCloseable(new HashedWheelTimer(getThreadFactoryDependency(), getTickDuration(), + unit)); + } + if (getTickDuration() != null && getThreadFactoryDependency() != null && getTicksPerWheel() != null) { + return new HashedWheelTimerCloseable(new HashedWheelTimer(getThreadFactoryDependency(), getTickDuration(), + unit, getTicksPerWheel())); + } + return new HashedWheelTimerCloseable(new HashedWheelTimer()); + } + + static final private class HashedWheelTimerCloseable implements AutoCloseable, Timer { + + private final Timer timer; + + public HashedWheelTimerCloseable(Timer timer) { + this.timer = timer; + } + + @Override + public void close() throws Exception { + stop(); + } + + @Override + public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { + return this.timer.newTimeout(task, delay, unit); + } + + @Override + public Set stop() { + return this.timer.stop(); + } + + } +} diff --git a/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleFactory.java b/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleFactory.java new file mode 100644 index 0000000000..e291ab5465 --- /dev/null +++ b/opendaylight/config/netty-timer-config/src/main/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleFactory.java @@ -0,0 +1,18 @@ +/** + * Generated file + + * Generated from: yang module name: netty-event-executor yang module local name: netty-hashed-wheel-timer + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Tue Nov 19 12:49:59 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.netty.timer; + +/** +* +*/ +public class HashedWheelTimerModuleFactory extends + org.opendaylight.controller.config.yang.netty.timer.AbstractHashedWheelTimerModuleFactory { + +} diff --git a/opendaylight/config/netty-timer-config/src/main/yang/netty-timer.yang b/opendaylight/config/netty-timer-config/src/main/yang/netty-timer.yang new file mode 100644 index 0000000000..b53b13f5a8 --- /dev/null +++ b/opendaylight/config/netty-timer-config/src/main/yang/netty-timer.yang @@ -0,0 +1,59 @@ +// vi: set smarttab et sw=4 tabstop=4: +module netty-timer { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:netty:timer"; + prefix "netty-timer"; + + import config { prefix config; revision-date 2013-04-05; } + import netty { prefix netty; revision-date 2013-11-19; } + import threadpool { prefix th; revision-date 2013-04-09; } + + organization "Cisco Systems, Inc."; + + contact "Milos Fabian "; + + description + "This module contains the base YANG definitions for + netty timer implementation. + + Copyright (c)2013 Cisco Systems, Inc. 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"; + + revision "2013-11-19" { + description + "Initial revision"; + } + + identity netty-hashed-wheel-timer { + base config:module-type; + config:provided-service netty:netty-timer; + config:java-name-prefix HashedWheelTimer; + } + + augment "/config:modules/config:module/config:configuration" { + case netty-hashed-wheel-timer { + when "/config:modules/config:module/config:type = 'netty-hashed-wheel-timer'"; + + leaf tick-duration { + type uint32; + } + + leaf ticks-per-wheel { + type uint16; + } + + container thread-factory { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity th:threadfactory; + } + } + } + } + } +} \ No newline at end of file diff --git a/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java b/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java new file mode 100644 index 0000000000..8bc4d95d60 --- /dev/null +++ b/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java @@ -0,0 +1,131 @@ +package org.opendaylight.controller.config.yang.netty.timer; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; +import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFactoryModuleFactory; +import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFactoryModuleMXBean; + +public class HashedWheelTimerModuleTest extends AbstractConfigTest { + + private HashedWheelTimerModuleFactory factory; + private NamingThreadFactoryModuleFactory threadFactory; + private final String instanceName = "hashed-wheel-timer1"; + + @Before + public void setUp() { + factory = new HashedWheelTimerModuleFactory(); + threadFactory = new NamingThreadFactoryModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory, threadFactory)); + } + + public void testValidationExceptionTickDuration() throws InstanceAlreadyExistsException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + try { + createInstance(transaction, instanceName, 0L, 10, true); + transaction.validateConfig(); + Assert.fail(); + } catch (ValidationException e) { + Assert.assertTrue(e.getMessage().contains("TickDuration value must be greater than 0")); + } + } + + public void testValidationExceptionTicksPerWheel() throws InstanceAlreadyExistsException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + try { + createInstance(transaction, instanceName, 500L, 0, true); + transaction.validateConfig(); + Assert.fail(); + } catch (ValidationException e) { + Assert.assertTrue(e.getMessage().contains("TicksPerWheel value must be greater than 0")); + } + } + + @Test + public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, + ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + createInstance(transaction, instanceName, 500L, 10, true); + createInstance(transaction, instanceName + 1, null, null, false); + createInstance(transaction, instanceName + 2, 500L, 10, false); + createInstance(transaction, instanceName + 3, 500L, null, false); + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(4, factory.getImplementationName()); + assertStatus(status, 5, 0, 0); + } + + @Test + public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, + ValidationException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName, 500L, 10, true); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 0, 0, 2); + } + + @Test + public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException, + ValidationException, InstanceNotFoundException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName, 500L, 10, true); + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + HashedWheelTimerModuleMXBean mxBean = transaction.newMBeanProxy( + transaction.lookupConfigBean(factory.getImplementationName(), instanceName), + HashedWheelTimerModuleMXBean.class); + mxBean.setTicksPerWheel(20); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 0, 1, 1); + } + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, + final Long tickDuration, final Integer ticksPerWheel, final boolean hasThreadfactory) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + HashedWheelTimerModuleMXBean mxBean = transaction + .newMBeanProxy(nameCreated, HashedWheelTimerModuleMXBean.class); + mxBean.setTickDuration(tickDuration); + mxBean.setTicksPerWheel(ticksPerWheel); + if (hasThreadfactory) { + mxBean.setThreadFactory(createThreadfactoryInstance(transaction, "thread-factory1", "th")); + } + return nameCreated; + } + + private ObjectName createThreadfactoryInstance(ConfigTransactionJMXClient transaction, String instanceName, + final String namePrefix) throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(threadFactory.getImplementationName(), instanceName); + NamingThreadFactoryModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated, + NamingThreadFactoryModuleMXBean.class); + mxBean.setNamePrefix(namePrefix); + return nameCreated; + } + +} diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 3f27ff1055..22be6f162b 100755 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -30,9 +30,11 @@ yang-test logback-config threadpool-config-api + netty-config-api threadpool-config-impl netty-threadgroup-config netty-event-executor-config + netty-timer-config diff --git a/opendaylight/config/threadpool-config-api/pom.xml b/opendaylight/config/threadpool-config-api/pom.xml index cddfb64830..5c70ac7958 100644 --- a/opendaylight/config/threadpool-config-api/pom.xml +++ b/opendaylight/config/threadpool-config-api/pom.xml @@ -22,10 +22,6 @@ com.google.guava guava - - io.netty - netty-transport - @@ -38,8 +34,6 @@ org.opendaylight.controller.config.api.*, com.google.common.eventbus, - io.netty.channel, - io.netty.util.concurrent org.opendaylight.controller.config.threadpool, diff --git a/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang b/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang index 9c73711c17..8f3064822b 100644 --- a/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang +++ b/opendaylight/config/threadpool-config-api/src/main/yang/threadpool.yang @@ -73,23 +73,4 @@ module threadpool { base "threadpool"; config:java-class "org.opendaylight.controller.config.threadpool.ScheduledThreadPool"; } - - - identity netty-threadgroup { - description - "Configuration wrapper around netty's threadgroup"; - - base "config:service-type"; - config:java-class "io.netty.channel.EventLoopGroup"; - } - - identity netty-event-executor { - description - "Configuration wrapper around netty's event executor"; - - base "config:service-type"; - config:java-class "io.netty.util.concurrent.EventExecutor"; - } - - } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java index 590081072b..70a4edde41 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java @@ -7,21 +7,8 @@ */ package org.opendaylight.controller.config.yangjmxgenerator; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static java.lang.String.format; -import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Sets; import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; @@ -50,8 +37,20 @@ import org.opendaylight.yangtools.yang.model.api.UsesNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Sets; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.lang.String.format; +import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName; /** * Represents part of yang model that describes a module. @@ -129,13 +128,13 @@ public class ModuleMXBeanEntry extends AbstractEntry { private final String nullableDescription, packageName, javaNamePrefix, namespace; - private final Map providedServices; + private final Map providedServices; private Collection runtimeBeans; public ModuleMXBeanEntry(IdentitySchemaNode id, Map yangToAttributes, String packageName, - Map providedServices2, String javaNamePrefix, + Map providedServices2, String javaNamePrefix, String namespace, Collection runtimeBeans) { this.globallyUniqueName = id.getQName().getLocalName(); this.yangToAttributes = yangToAttributes; @@ -180,7 +179,11 @@ public class ModuleMXBeanEntry extends AbstractEntry { return packageName; } - public Map getProvidedServices() { + /** + * @return services implemented by this module. Keys are fully qualified java names of generated + * ServiceInterface classes, values are identity local names. + */ + public Map getProvidedServices() { return providedServices; } @@ -313,7 +316,7 @@ public class ModuleMXBeanEntry extends AbstractEntry { checkState(moduleIdentity != null, "Cannot find identity " + moduleLocalNameFromXPath + " matching augmentation " + augmentation); - Map providedServices = findProvidedServices( + Map providedServices = findProvidedServices( moduleIdentity, currentModule, qNamesToSIEs, schemaContext); @@ -493,11 +496,11 @@ public class ModuleMXBeanEntry extends AbstractEntry { return yangToAttributes; } - private static Map findProvidedServices( + private static Map findProvidedServices( IdentitySchemaNode moduleIdentity, Module currentModule, Map qNamesToSIEs, SchemaContext schemaContext) { - Map result = new HashMap<>(); + Map result = new HashMap<>(); for (UnknownSchemaNode unknownNode : moduleIdentity .getUnknownSchemaNodes()) { if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME @@ -506,8 +509,7 @@ public class ModuleMXBeanEntry extends AbstractEntry { .getNodeParameter(); ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName, currentModule, qNamesToSIEs, schemaContext); - result.put(sie.getFullyQualifiedName(), sie.getQName() - .getLocalName()); + result.put(sie.getFullyQualifiedName(), sie.getQName()); } } return result; diff --git a/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreSnapshot.java b/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreSnapshot.java index 40daf4018a..da8b5e4ed1 100644 --- a/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreSnapshot.java +++ b/opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreSnapshot.java @@ -15,7 +15,8 @@ import org.opendaylight.yangtools.yang.model.api.Module; public interface YangStoreSnapshot extends AutoCloseable { - Map> getModuleMXBeanEntryMap(); + Map> getModuleMXBeanEntryMap(); Map> getModuleMap(); diff --git a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java index 2ead596d05..9356dd3752 100644 --- a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java +++ b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java @@ -18,6 +18,8 @@ import com.google.common.collect.Sets; import org.opendaylight.controller.config.yang.store.api.YangStoreException; import org.opendaylight.controller.config.yang.store.api.YangStoreService; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; +import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; +import org.opendaylight.yangtools.yang.model.api.Module; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; @@ -34,6 +36,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -107,38 +110,42 @@ public class ExtenderYangTracker extends BundleTracker implements YangSt proposedNewState.putAll(bundle, addedURLs); Preconditions.checkArgument(addedURLs.size() > 0, "No change can occur when no URLs are changed"); - boolean success; - String failureReason = null; + try(YangStoreSnapshotImpl snapshot = createSnapshot(mbeParser, proposedNewState)) { - updateCache(snapshot); - success = true; + onSnapshotSuccess(proposedNewState, snapshot); } catch(YangStoreException e) { - failureReason = e.toString(); - success = false; - } - if (success){ - // consistent state - // merge into - consistentBundlesToYangURLs.clear(); - consistentBundlesToYangURLs.putAll(proposedNewState); - inconsistentBundlesToYangURLs.clear(); - - logger.info("Yang store updated to new consistent state containing {} yang files", consistentBundlesToYangURLs.size()); - logger.trace("Yang store updated to new consistent state containing {}", consistentBundlesToYangURLs); - } else { - // inconsistent state - logger.debug("Yang store is falling back on last consistent state containing {}, inconsistent yang files {}, reason {}", - consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, failureReason); - logger.warn("Yang store is falling back on last consistent state containing {} files, inconsistent yang files size is {}, reason {}", - consistentBundlesToYangURLs.size(), inconsistentBundlesToYangURLs.size(), failureReason); - inconsistentBundlesToYangURLs.putAll(bundle, addedURLs); + onSnapshotFailure(bundle, addedURLs, e); } } } return bundle; } - private void updateCache(YangStoreSnapshotImpl snapshot) { + private synchronized void onSnapshotFailure(Bundle bundle, List addedURLs, Exception failureReason) { + // inconsistent state + inconsistentBundlesToYangURLs.putAll(bundle, addedURLs); + + logger.debug("Yang store is falling back on last consistent state containing {}, inconsistent yang files {}", + consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, failureReason); + logger.warn("Yang store is falling back on last consistent state containing {} files, inconsistent yang files size is {}, reason {}", + consistentBundlesToYangURLs.size(), inconsistentBundlesToYangURLs.size(), failureReason.toString()); + cache.setInconsistentURLsForReporting(inconsistentBundlesToYangURLs.values()); + } + + private synchronized void onSnapshotSuccess(Multimap proposedNewState, YangStoreSnapshotImpl snapshot) { + // consistent state + // merge into + consistentBundlesToYangURLs.clear(); + consistentBundlesToYangURLs.putAll(proposedNewState); + inconsistentBundlesToYangURLs.clear(); + + updateCache(snapshot); + cache.setInconsistentURLsForReporting(Collections. emptySet()); + logger.info("Yang store updated to new consistent state containing {} yang files", consistentBundlesToYangURLs.size()); + logger.debug("Yang store updated to new consistent state containing {}", consistentBundlesToYangURLs); + } + + private synchronized void updateCache(YangStoreSnapshotImpl snapshot) { cache.cacheYangStore(consistentBundlesToYangURLs, snapshot); } @@ -153,6 +160,7 @@ public class ExtenderYangTracker extends BundleTracker implements YangSt */ @Override public synchronized void removedBundle(Bundle bundle, BundleEvent event, Object object) { + logger.debug("Removed bundle {} {} {}", bundle, event, object); inconsistentBundlesToYangURLs.removeAll(bundle); consistentBundlesToYangURLs.removeAll(bundle); } @@ -162,9 +170,10 @@ public class ExtenderYangTracker extends BundleTracker implements YangSt throws YangStoreException { Optional yangStoreOpt = cache.getSnapshotIfPossible(consistentBundlesToYangURLs); if (yangStoreOpt.isPresent()) { - logger.trace("Returning cached yang store {}", yangStoreOpt.get()); + logger.debug("Returning cached yang store {}", yangStoreOpt.get()); return yangStoreOpt.get(); } + YangStoreSnapshotImpl snapshot = createSnapshot(mbeParser, consistentBundlesToYangURLs); updateCache(snapshot); return snapshot; @@ -205,18 +214,27 @@ public class ExtenderYangTracker extends BundleTracker implements YangSt } class YangStoreCache { + private static final Logger logger = LoggerFactory.getLogger(YangStoreCache.class); + + @GuardedBy("this") + private Set cachedUrls = null; @GuardedBy("this") - private Set cachedUrls = Collections.emptySet(); + private Optional cachedYangStoreSnapshot = getInitialSnapshot(); @GuardedBy("this") - private Optional cachedYangStoreSnapshot = Optional.absent(); + private Collection inconsistentURLsForReporting = Collections.emptySet(); synchronized Optional getSnapshotIfPossible(Multimap bundlesToYangURLs) { Set urls = setFromMultimapValues(bundlesToYangURLs); - if (cachedUrls != null && cachedUrls.equals(urls)) { + + if (cachedUrls==null || cachedUrls.equals(urls)) { Preconditions.checkState(cachedYangStoreSnapshot.isPresent()); YangStoreSnapshot freshSnapshot = new YangStoreSnapshotImpl(cachedYangStoreSnapshot.get()); + if (inconsistentURLsForReporting.size() > 0){ + logger.warn("Some yang URLs are ignored: {}", inconsistentURLsForReporting); + } return Optional.of(freshSnapshot); } + return Optional.absent(); } @@ -228,7 +246,7 @@ class YangStoreCache { } synchronized void cacheYangStore(Multimap urls, - YangStoreSnapshotImpl yangStoreSnapshot) { + YangStoreSnapshot yangStoreSnapshot) { this.cachedUrls = setFromMultimapValues(urls); this.cachedYangStoreSnapshot = Optional.of(yangStoreSnapshot); } @@ -240,4 +258,32 @@ class YangStoreCache { cachedYangStoreSnapshot = Optional.absent(); } } + + public synchronized void setInconsistentURLsForReporting(Collection urls){ + inconsistentURLsForReporting = urls; + } + + private Optional getInitialSnapshot() { + YangStoreSnapshot initialSnapshot = new YangStoreSnapshot() { + @Override + public Map> getModuleMXBeanEntryMap() { + return Collections.emptyMap(); + } + + @Override + public Map> getModuleMap() { + return Collections.emptyMap(); + } + + @Override + public int countModuleMXBeanEntries() { + return 0; + } + + @Override + public void close() { + } + }; + return Optional.of(initialSnapshot); + } } diff --git a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreSnapshotImpl.java b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreSnapshotImpl.java index 7a5ca7debe..ea709e1a45 100644 --- a/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreSnapshotImpl.java +++ b/opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreSnapshotImpl.java @@ -29,11 +29,15 @@ public class YangStoreSnapshotImpl implements YangStoreSnapshot { this.moduleMap = Collections.unmodifiableMap(moduleMap); } - public YangStoreSnapshotImpl(YangStoreSnapshotImpl yangStoreSnapshot) { - this.moduleMXBeanEntryMap = yangStoreSnapshot.moduleMXBeanEntryMap; - this.moduleMap = yangStoreSnapshot.moduleMap; + public YangStoreSnapshotImpl(YangStoreSnapshot yangStoreSnapshot) { + this.moduleMXBeanEntryMap = yangStoreSnapshot.getModuleMXBeanEntryMap(); + this.moduleMap = yangStoreSnapshot.getModuleMap(); } + /** + * @return all loaded config modules. Key of outer map is namespace of yang file. + * Key of inner map is name of module entry. Value is module entry. + */ @Override public Map> getModuleMXBeanEntryMap() { return moduleMXBeanEntryMap; diff --git a/opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTrackerCustomizerTest.java b/opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTrackerCustomizerTest.java index c4c523992f..b4054c242c 100644 --- a/opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTrackerCustomizerTest.java +++ b/opendaylight/config/yang-store-impl/src/test/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTrackerCustomizerTest.java @@ -9,12 +9,14 @@ package org.opendaylight.controller.config.yang.store.impl; import com.google.common.base.Optional; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.config.yang.store.api.YangStoreException; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; +import org.opendaylight.yangtools.yang.model.api.Module; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleListener; @@ -25,6 +27,7 @@ import java.net.URL; import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; import static org.junit.Assert.assertEquals; @@ -48,8 +51,28 @@ public class ExtenderYangTrackerCustomizerTest { @Mock private BundleContext bundleContext; + private Map> moduleMap = Maps.newHashMap(); + @Before public void setUp() throws YangStoreException { + + moduleMap.put("1", new Map.Entry() { + @Override + public Module getKey() { + return mock(Module.class); + } + + @Override + public String getValue() { + return "v"; + } + + @Override + public String setValue(String value) { + return "v"; + } + }); + MockitoAnnotations.initMocks(this); doNothing().when(bundleContext).addBundleListener(any(BundleListener.class)); doReturn(new Bundle[0]).when(bundleContext).getBundles(); @@ -59,7 +82,8 @@ public class ExtenderYangTrackerCustomizerTest { doReturn(22).when(yangStoreSnapshot).countModuleMXBeanEntries(); doReturn("mock yang store").when(yangStoreSnapshot).toString(); doNothing().when(yangStoreSnapshot).close(); - doReturn(Collections.emptyMap()).when(yangStoreSnapshot).getModuleMap(); + doReturn(moduleMap).when(yangStoreSnapshot).getModuleMap(); + doReturn(Collections.emptyMap()).when(yangStoreSnapshot).getModuleMXBeanEntryMap(); } @Test @@ -75,7 +99,7 @@ public class ExtenderYangTrackerCustomizerTest { returnedStore = tested.getYangStoreSnapshot(); - assertEquals(yangStoreSnapshot, returnedStore); + assertEquals(yangStoreSnapshot.getModuleMap(), returnedStore.getModuleMap()); tested.removedBundle(bundle, null, null); tested.getYangStoreSnapshot(); @@ -87,7 +111,7 @@ public class ExtenderYangTrackerCustomizerTest { tested.getYangStoreSnapshot(); } - verify(parser, times(7)).parseYangFiles(anyCollectionOf(InputStream.class)); + verify(parser, times(5)).parseYangFiles(anyCollectionOf(InputStream.class)); returnedStore = tested.getYangStoreSnapshot(); diff --git a/opendaylight/configuration/integrationtest/pom.xml b/opendaylight/configuration/integrationtest/pom.xml index 788c8e8a09..894f94bc46 100644 --- a/opendaylight/configuration/integrationtest/pom.xml +++ b/opendaylight/configuration/integrationtest/pom.xml @@ -84,7 +84,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerFlowConfig.java b/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerFlowConfig.java index baa2c78253..9740a92598 100644 --- a/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerFlowConfig.java +++ b/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/ContainerFlowConfig.java @@ -114,6 +114,17 @@ public class ContainerFlowConfig implements Serializable { //this.unidirectional = false; } + public ContainerFlowConfig(String name, String dlVlan, String srcIP, String dstIP, String proto, String srcPort, + String dstPort) { + this.name = name; + this.dlVlan = dlVlan; + this.nwSrc = srcIP; + this.nwDst = dstIP; + this.protocol = proto; + this.tpSrc = srcPort; + this.tpDst = dstPort; + } + public ContainerFlowConfig(ContainerFlowConfig containerFlowConfig) { this.name = containerFlowConfig.name; diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 75424ba1b6..55ab5caeeb 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -242,6 +242,11 @@ threadpool-config-api ${config.version} + + org.opendaylight.controller + netty-config-api + ${config.version} + org.opendaylight.controller threadpool-config-impl @@ -249,7 +254,7 @@ org.opendaylight.controller - netty-event-executor-config + netty-threadgroup-config ${config.version} @@ -257,6 +262,11 @@ netty-event-executor-config ${config.version} + + org.opendaylight.controller + netty-timer-config + ${config.version} + @@ -446,7 +456,7 @@ org.opendaylight.controller forwarding.staticrouting - ${controller.version} + ${forwarding.staticrouting} org.opendaylight.controller @@ -476,17 +486,17 @@ org.opendaylight.controller arphandler - ${controller.version} + ${arphandler.version} org.opendaylight.controller hosttracker - ${controller.version} + ${hosttracker.version} org.opendaylight.controller hosttracker.implementation - ${controller.version} + ${hosttracker.version} org.opendaylight.controller @@ -762,7 +772,7 @@ org.opendaylight.controller samples.loadbalancer - ${controller.version} + ${samples.loadbalancer} org.opendaylight.controller diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index dacdd2546e..bfc3962040 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -22,7 +22,9 @@ netconf.tcp.port=8383 #netconf.tls.keystore= #netconf.tls.keystore.password= -netconf.config.persister.storageAdapterClass=org.opendaylight.controller.netconf.persist.impl.NoOpStorageAdapter +netconf.config.persister.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter +fileStorage=configuration/controller.config +numberOfBackups=1 yangstore.blacklist=.*controller.model.* # Set Default start level for framework @@ -115,3 +117,6 @@ org.jolokia.listenForHttpService=false # Logging configuration for Tomcat-JUL logging java.util.logging.config.file=configuration/tomcat-logging.properties + +#Hosttracker hostsdb key scheme setting +hosttracker.keyscheme=IP diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config b/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config new file mode 100644 index 0000000000..947c15b35c --- /dev/null +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config @@ -0,0 +1,127 @@ +//START OF CONFIG-LAST + + + + prefix:schema-service-singleton + yang-schema-service + + + prefix:hash-map-data-store + hash-map-data-store + + + prefix:dom-broker-impl + dom-broker + + dom:dom-data-store + ref_hash-map-data-store + + + + prefix:binding-broker-impl + binding-broker-impl + + binding:binding-notification-service + ref_binding-notification-broker + + + binding:binding-data-broker + ref_binding-data-broker + + + + prefix:runtime-generated-mapping + runtime-mapping-singleton + + + prefix:binding-notification-broker + binding-notification-broker + + + prefix:binding-data-broker + binding-data-broker + + dom:dom-broker-osgi-registry + ref_dom-broker + + + binding:binding-dom-mapping-service + ref_runtime-mapping-singleton + + + + + + dom:schema-service + + ref_yang-schema-service + /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] + + + + binding:binding-notification-service + + ref_binding-notification-broker + /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] + + + + dom:dom-data-store + + ref_hash-map-data-store + /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] + + + + binding:binding-broker-osgi-registry + + ref_binding-broker-impl + /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] + + + + binding-impl:binding-dom-mapping-service + + ref_runtime-mapping-singleton + /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] + + + + dom:dom-broker-osgi-registry + + ref_dom-broker + /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] + + + + binding:binding-data-broker + + ref_binding-data-broker + /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] + + + + + +//END OF SNAPSHOT +urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 +urn:ietf:params:netconf:capability:candidate:1.0 +urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 +urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12 +urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 +urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 +urn:ietf:params:netconf:capability:rollback-on-error:1.0 +urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 +urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 +urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 +urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19 +//END OF CONFIG diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml index c61b41c065..3ad0c61d4f 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml @@ -62,6 +62,8 @@ + + diff --git a/opendaylight/forwarding/staticrouting/pom.xml b/opendaylight/forwarding/staticrouting/pom.xml index bee0da2496..f160cddaad 100644 --- a/opendaylight/forwarding/staticrouting/pom.xml +++ b/opendaylight/forwarding/staticrouting/pom.xml @@ -1,90 +1,92 @@ - - 4.0.0 - - org.opendaylight.controller - commons.opendaylight - 1.4.1-SNAPSHOT - ../../commons/opendaylight - - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main - HEAD - + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.1-SNAPSHOT + ../../commons/opendaylight + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main + HEAD + - forwarding.staticrouting - 0.4.1-SNAPSHOT - bundle + forwarding.staticrouting + 0.5.1-SNAPSHOT + bundle - - - - org.apache.felix - maven-bundle-plugin - ${bundle.plugin.version} - true - - - - org.opendaylight.controller.sal.utils, - org.opendaylight.controller.sal.core, - org.opendaylight.controller.configuration, - org.opendaylight.controller.forwardingrulesmanager, - org.opendaylight.controller.hosttracker, - org.opendaylight.controller.hosttracker.hostAware, - org.opendaylight.controller.clustering.services, - org.opendaylight.controller.sal.packet, - org.opendaylight.controller.sal.routing, - org.opendaylight.controller.topologymanager, - org.eclipse.osgi.framework.console, - org.osgi.framework, - org.slf4j, - org.apache.felix.dm, - org.apache.commons.lang3.builder - - - org.opendaylight.controller.forwarding.staticrouting - - - org.opendaylight.controller.forwarding.staticrouting.internal.Activator - - - ${project.basedir}/META-INF - - - - - - - org.opendaylight.controller - topologymanager - 0.4.1-SNAPSHOT - - - org.opendaylight.controller - forwardingrulesmanager - 0.4.1-SNAPSHOT - - - org.opendaylight.controller - hosttracker - 0.4.1-SNAPSHOT - - - org.opendaylight.controller - configuration - 0.4.1-SNAPSHOT - - - junit - junit - - - org.opendaylight.controller - sal - 0.5.1-SNAPSHOT - - + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + true + + + + org.opendaylight.controller.sal.packet.address, + org.opendaylight.controller.sal.utils, + org.opendaylight.controller.sal.core, + org.opendaylight.controller.configuration, + org.opendaylight.controller.forwardingrulesmanager, + org.opendaylight.controller.hosttracker, + org.opendaylight.controller.hosttracker.hostAware, + org.opendaylight.controller.clustering.services, + org.opendaylight.controller.sal.packet, + org.opendaylight.controller.sal.routing, + org.opendaylight.controller.topologymanager, + org.eclipse.osgi.framework.console, + org.osgi.framework, + org.slf4j, + org.apache.felix.dm, + org.apache.commons.lang3.builder + + + org.opendaylight.controller.forwarding.staticrouting + + + org.opendaylight.controller.forwarding.staticrouting.internal.Activator + + + ${project.basedir}/META-INF + + + + + + + org.opendaylight.controller + topologymanager + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + forwardingrulesmanager + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + hosttracker + ${hosttracker.version} + + + org.opendaylight.controller + configuration + 0.4.1-SNAPSHOT + + + junit + junit + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + diff --git a/opendaylight/forwarding/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/internal/StaticRoutingImplementation.java b/opendaylight/forwarding/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/internal/StaticRoutingImplementation.java index 315543514e..2ce2465d97 100644 --- a/opendaylight/forwarding/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/internal/StaticRoutingImplementation.java +++ b/opendaylight/forwarding/staticrouting/src/main/java/org/opendaylight/controller/forwarding/staticrouting/internal/StaticRoutingImplementation.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -42,6 +41,8 @@ import org.opendaylight.controller.forwarding.staticrouting.IForwardingStaticRou import org.opendaylight.controller.forwarding.staticrouting.IStaticRoutingAware; import org.opendaylight.controller.forwarding.staticrouting.StaticRoute; import org.opendaylight.controller.forwarding.staticrouting.StaticRouteConfig; +import org.opendaylight.controller.hosttracker.HostIdFactory; +import org.opendaylight.controller.hosttracker.IHostId; import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.IfNewHostNotify; import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; @@ -57,10 +58,9 @@ import org.slf4j.LoggerFactory; /** * Static Routing feature provides the bridge between SDN and Non-SDN networks. */ -public class StaticRoutingImplementation implements IfNewHostNotify, - IForwardingStaticRouting, IObjectReader, IConfigurationContainerAware { - private static Logger log = LoggerFactory - .getLogger(StaticRoutingImplementation.class); +public class StaticRoutingImplementation implements IfNewHostNotify, IForwardingStaticRouting, IObjectReader, + IConfigurationContainerAware { + private static Logger log = LoggerFactory.getLogger(StaticRoutingImplementation.class); private static String ROOT = GlobalConstants.STARTUPHOME.toString(); ConcurrentMap staticRoutes; ConcurrentMap staticRouteConfigs; @@ -101,8 +101,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify, } @Override - public Object readObject(ObjectInputStream ois) - throws FileNotFoundException, IOException, ClassNotFoundException { + public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException { // Perform the class deserialization locally, from inside the package // where the class is defined return ois.readObject(); @@ -111,8 +110,8 @@ public class StaticRoutingImplementation implements IfNewHostNotify, @SuppressWarnings("unchecked") private void loadConfiguration() { ObjectReader objReader = new ObjectReader(); - ConcurrentMap confList = (ConcurrentMap) objReader - .read(this, staticRoutesFileName); + ConcurrentMap confList = (ConcurrentMap) objReader.read( + this, staticRoutesFileName); if (confList == null) { return; @@ -123,7 +122,6 @@ public class StaticRoutingImplementation implements IfNewHostNotify, } } - private Status saveConfig() { return saveConfigInternal(); } @@ -132,9 +130,8 @@ public class StaticRoutingImplementation implements IfNewHostNotify, Status status; ObjectWriter objWriter = new ObjectWriter(); - status = objWriter.write( - new ConcurrentHashMap( - staticRouteConfigs), staticRoutesFileName); + status = objWriter.write(new ConcurrentHashMap(staticRouteConfigs), + staticRoutesFileName); if (status.isSuccess()) { return status; @@ -144,23 +141,19 @@ public class StaticRoutingImplementation implements IfNewHostNotify, } @SuppressWarnings("deprecation") - private void allocateCaches() { + private void allocateCaches() { if (this.clusterContainerService == null) { - log - .info("un-initialized clusterContainerService, can't create cache"); + log.info("un-initialized clusterContainerService, can't create cache"); return; } try { - clusterContainerService.createCache( - "forwarding.staticrouting.routes", EnumSet - .of(IClusterServices.cacheMode.TRANSACTIONAL)); - clusterContainerService.createCache( - "forwarding.staticrouting.configs", EnumSet - .of(IClusterServices.cacheMode.TRANSACTIONAL)); + clusterContainerService.createCache("forwarding.staticrouting.routes", + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); + clusterContainerService.createCache("forwarding.staticrouting.configs", + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); } catch (CacheExistException cee) { - log - .error("\nCache already exists - destroy and recreate if needed"); + log.error("\nCache already exists - destroy and recreate if needed"); } catch (CacheConfigException cce) { log.error("\nCache configuration invalid - check cache mode"); } @@ -169,8 +162,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify, @SuppressWarnings({ "unchecked", "deprecation" }) private void retrieveCaches() { if (this.clusterContainerService == null) { - log - .info("un-initialized clusterContainerService, can't retrieve cache"); + log.info("un-initialized clusterContainerService, can't retrieve cache"); return; } @@ -195,7 +187,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify, try { ra.staticRouteUpdate(s, update); } catch (Exception e) { - log.error("",e); + log.error("", e); } } } @@ -216,15 +208,16 @@ public class StaticRoutingImplementation implements IfNewHostNotify, @Override public Object call() throws Exception { - if (!added - || (staticRoute.getType() == StaticRoute.NextHopType.SWITCHPORT)) { + if (!added || (staticRoute.getType() == StaticRoute.NextHopType.SWITCHPORT)) { notifyStaticRouteUpdate(staticRoute, added); } else { InetAddress nh = staticRoute.getNextHopAddress(); - HostNodeConnector host = hostTracker.hostQuery(nh); + // HostTracker hosts db key scheme implementation + IHostId id = HostIdFactory.create(nh, null); + HostNodeConnector host = hostTracker.hostQuery(id); if (host == null) { log.debug("Next hop {} is not present, try to discover it", nh.getHostAddress()); - Future future = hostTracker.discoverHost(nh); + Future future = hostTracker.discoverHost(id); if (future != null) { try { host = future.get(); @@ -337,8 +330,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify, public StaticRoute getBestMatchStaticRoute(InetAddress ipAddress) { ByteBuffer bblongestPrefix = null; try { - bblongestPrefix = ByteBuffer.wrap(InetAddress.getByName("0.0.0.0") - .getAddress()); + bblongestPrefix = ByteBuffer.wrap(InetAddress.getByName("0.0.0.0").getAddress()); } catch (Exception e) { return null; } @@ -368,9 +360,8 @@ public class StaticRoutingImplementation implements IfNewHostNotify, return status; } if (staticRouteConfigs.get(config.getName()) != null) { - return new Status(StatusCode.CONFLICT, - "A valid Static Route configuration with this name " + - "already exists. Please use a different name"); + return new Status(StatusCode.CONFLICT, "A valid Static Route configuration with this name " + + "already exists. Please use a different name"); } // Update database @@ -378,10 +369,8 @@ public class StaticRoutingImplementation implements IfNewHostNotify, for (Map.Entry entry : staticRoutes.entrySet()) { if (entry.getValue().compareTo(sRoute) == 0) { - return new Status(StatusCode.CONFLICT, - "This conflicts with an existing Static Route " + - "Configuration. Please check the configuration " + - "and try again"); + return new Status(StatusCode.CONFLICT, "This conflicts with an existing Static Route " + + "Configuration. Please check the configuration " + "and try again"); } } staticRoutes.put(config.getName(), sRoute); @@ -402,8 +391,7 @@ public class StaticRoutingImplementation implements IfNewHostNotify, checkAndUpdateListeners(name, sRoute, false); return new Status(StatusCode.SUCCESS, null); } - return new Status(StatusCode.NOTFOUND, - "Static Route with name " + name + " is not found"); + return new Status(StatusCode.NOTFOUND, "Static Route with name " + name + " is not found"); } void setClusterContainerService(IClusterContainerServices s) { @@ -433,11 +421,9 @@ public class StaticRoutingImplementation implements IfNewHostNotify, containerName = ""; } - staticRoutesFileName = ROOT + "staticRouting_" + containerName - + ".conf"; + staticRoutesFileName = ROOT + "staticRouting_" + containerName + ".conf"; - log.debug("forwarding.staticrouting starting on container {}", - containerName); + log.debug("forwarding.staticrouting starting on container {}", containerName); allocateCaches(); retrieveCaches(); this.executor = Executors.newFixedThreadPool(1); @@ -446,8 +432,8 @@ public class StaticRoutingImplementation implements IfNewHostNotify, } /* - * Slow probe to identify any gateway that might have silently appeared - * after the Static Routing Configuration. + * Slow probe to identify any gateway that might have silently appeared + * after the Static Routing Configuration. */ gatewayProbeTimer = new Timer(); gatewayProbeTimer.schedule(new TimerTask() { @@ -455,24 +441,23 @@ public class StaticRoutingImplementation implements IfNewHostNotify, public void run() { for (Map.Entry s : staticRoutes.entrySet()) { StaticRoute route = s.getValue(); - if ((route.getType() == StaticRoute.NextHopType.IPADDRESS) - && route.getHost() == null) { + if ((route.getType() == StaticRoute.NextHopType.IPADDRESS) && route.getHost() == null) { checkAndUpdateListeners(s.getKey(), route, true); } } } }, 60 * 1000, 60 * 1000); + } /** - * Function called by the dependency manager when at least one - * dependency become unsatisfied or when the component is shutting - * down because for example bundle is being stopped. + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. * */ void destroy() { - log.debug("Destroy all the Static Routing Rules given we are " - + "shutting down"); + log.debug("Destroy all the Static Routing Rules given we are " + "shutting down"); gatewayProbeTimer.cancel(); @@ -481,18 +466,17 @@ public class StaticRoutingImplementation implements IfNewHostNotify, } /** - * Function called by dependency manager after "init ()" is called - * and after the services provided by the class are registered in - * the service registry + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry * */ void start() { } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls * */ void stop() { diff --git a/opendaylight/forwardingrulesmanager/api/pom.xml b/opendaylight/forwardingrulesmanager/api/pom.xml index 2de9287670..f25756cc11 100644 --- a/opendaylight/forwardingrulesmanager/api/pom.xml +++ b/opendaylight/forwardingrulesmanager/api/pom.xml @@ -68,7 +68,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/forwardingrulesmanager/implementation/pom.xml b/opendaylight/forwardingrulesmanager/implementation/pom.xml index 613c2f164f..23c36a3752 100644 --- a/opendaylight/forwardingrulesmanager/implementation/pom.xml +++ b/opendaylight/forwardingrulesmanager/implementation/pom.xml @@ -74,7 +74,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/forwardingrulesmanager/integrationtest/pom.xml b/opendaylight/forwardingrulesmanager/integrationtest/pom.xml index 15b31d5ea6..7904bd3a8f 100644 --- a/opendaylight/forwardingrulesmanager/integrationtest/pom.xml +++ b/opendaylight/forwardingrulesmanager/integrationtest/pom.xml @@ -21,12 +21,12 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller hosttracker.implementation - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/hosttracker/api/pom.xml b/opendaylight/hosttracker/api/pom.xml index 5846aa3d1a..ea66c34fa3 100644 --- a/opendaylight/hosttracker/api/pom.xml +++ b/opendaylight/hosttracker/api/pom.xml @@ -1,81 +1,82 @@ - 4.0.0 - - org.opendaylight.controller - commons.opendaylight - 1.4.1-SNAPSHOT - ../../commons/opendaylight - - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main - HEAD - - hosttracker - 0.4.1-SNAPSHOT - bundle + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.1-SNAPSHOT + ../../commons/opendaylight + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main + HEAD + + hosttracker + 0.5.1-SNAPSHOT + bundle - - - - org.apache.felix - maven-bundle-plugin - ${bundle.plugin.version} - true - - - - org.opendaylight.controller.hosttracker, - org.opendaylight.controller.hosttracker.hostAware - - - org.opendaylight.controller.sal.core, - org.opendaylight.controller.sal.utils, - org.opendaylight.controller.topologymanager, - org.opendaylight.controller.sal.packet.address, - org.opendaylight.controller.switchmanager, - org.opendaylight.controller.clustering.services, - javax.xml.bind.annotation, - javax.xml.bind, - org.apache.felix.dm, - org.apache.commons.lang3.builder, - org.osgi.service.component, - org.slf4j, - org.eclipse.osgi.framework.console, - org.osgi.framework - - - ${project.basedir}/META-INF - - - - - - - org.opendaylight.controller - topologymanager - 0.4.1-SNAPSHOT - - - org.opendaylight.controller - switchmanager - - - org.opendaylight.controller - clustering.services - 0.4.1-SNAPSHOT - - - org.opendaylight.controller - sal - 0.5.1-SNAPSHOT - - - junit - junit - - + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + true + + + + org.opendaylight.controller.hosttracker, + org.opendaylight.controller.hosttracker.hostAware + + + org.opendaylight.controller.sal.core, + org.opendaylight.controller.sal.utils, + org.opendaylight.controller.topologymanager, + org.opendaylight.controller.sal.packet.address, + org.opendaylight.controller.switchmanager, + org.opendaylight.controller.clustering.services, + javax.xml.bind.annotation, + javax.xml.bind, + org.apache.felix.dm, + org.apache.commons.lang3.builder, + org.osgi.service.component, + org.slf4j, + org.eclipse.osgi.framework.console, + org.osgi.framework + + + ${project.basedir}/META-INF + + + + + + + org.opendaylight.controller + topologymanager + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + switchmanager + + + org.opendaylight.controller + clustering.services + 0.4.1-SNAPSHOT + + + org.opendaylight.controller + sal + 0.5.1-SNAPSHOT + + + junit + junit + + + diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/HostIdFactory.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/HostIdFactory.java new file mode 100644 index 0000000000..4585306214 --- /dev/null +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/HostIdFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright IBM Corporation, 2013. 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.hosttracker; + +import java.net.InetAddress; + +import org.opendaylight.controller.sal.packet.address.DataLinkAddress; + +/* + * Class used to generate a key based on the scheme choosen for hostsdb storage in hosttracker. + * @author Deepak Udapudi + */ +public class HostIdFactory { + public static final String DEFAULT_IP_KEY_SCHEME = "IP"; + public static final String IP_MAC_KEY_SCHEME = "IP+MAC"; + private static String scheme = null; + static { + scheme = System.getProperty("hosttracker.keyscheme"); + } + + public static String getScheme() { + return scheme; + } + + public static IHostId create(InetAddress ip, DataLinkAddress mac) { + IHostId ipHostId = new IPHostId(ip); + if (scheme != null) { + switch (scheme) { + + case DEFAULT_IP_KEY_SCHEME: + return ipHostId; + case IP_MAC_KEY_SCHEME: + IHostId ipMacHostId = new IPMacHostId(ip, mac); + return ipMacHostId; + default: + return ipHostId; + + } + } + return ipHostId; + } + +} diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IHostId.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IHostId.java new file mode 100644 index 0000000000..03f409e737 --- /dev/null +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IHostId.java @@ -0,0 +1,19 @@ +/* + * Copyright IBM Corporation, 2013. 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.hosttracker; + +import java.io.Serializable; + +/* + * Marker interface used by the key classes for their implementation + * @author Deepak Udapudi + */ + +public interface IHostId extends Serializable { + +} diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java new file mode 100644 index 0000000000..9e2123c6cd --- /dev/null +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java @@ -0,0 +1,64 @@ +/* + * Copyright IBM Corporation, 2013. 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.hosttracker; + +import java.io.Serializable; +import java.net.InetAddress; + +/* + * IP only key class implementation using the marker interface IHostId + * @author Deepak Udapudi + */ + +public class IPHostId implements IHostId, Serializable { + private static final long serialVersionUID = 1L; + private InetAddress ipAddress; + + public InetAddress getIpAddress() { + return ipAddress; + } + + public void setIpAddress(InetAddress ipAddress) { + this.ipAddress = ipAddress; + } + + public IPHostId(InetAddress ipAddress) { + super(); + this.ipAddress = ipAddress; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + IPHostId other = (IPHostId) obj; + if (ipAddress == null) { + if (other.ipAddress != null) + return false; + } else if (!ipAddress.equals(other.ipAddress)) + return false; + return true; + } + + public static IHostId fromIP(InetAddress addr) { + return new IPHostId(addr); + } + +} diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java new file mode 100644 index 0000000000..4ab84eb653 --- /dev/null +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java @@ -0,0 +1,83 @@ +/* + * Copyright IBM Corporation, 2013. 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.hosttracker; + +import java.io.Serializable; +import java.net.InetAddress; + +/* + * IP + Mac key class implementation using the marker interface IHostId + * @author Deepak Udapudi + */ + +import org.opendaylight.controller.sal.packet.address.DataLinkAddress; + +public class IPMacHostId implements IHostId, Serializable { + + private static final long serialVersionUID = 1L; + private InetAddress ipAddress; + private DataLinkAddress macAddr; + + public IPMacHostId(InetAddress ipAddress, DataLinkAddress macAddr) { + super(); + this.ipAddress = ipAddress; + this.macAddr = macAddr; + } + + public InetAddress getIpAddress() { + return ipAddress; + } + + public void setIpAddress(InetAddress ipAddress) { + this.ipAddress = ipAddress; + } + + public DataLinkAddress getMacAddr() { + return macAddr; + } + + public void setMacAddr(DataLinkAddress macAddr) { + this.macAddr = macAddr; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode()); + result = prime * result + ((macAddr == null) ? 0 : macAddr.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + IPMacHostId other = (IPMacHostId) obj; + if (ipAddress == null) { + if (other.ipAddress != null) + return false; + } else if (!ipAddress.equals(other.ipAddress)) + return false; + if (macAddr == null) { + if (other.macAddr != null) + return false; + } else if (!macAddr.equals(other.macAddr)) + return false; + return true; + } + + public static IHostId fromIPAndMac(InetAddress ip, DataLinkAddress mac) { + return new IPMacHostId(ip, mac); + } + +} diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IfIptoHost.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IfIptoHost.java index 2451e196f2..e70a6e1865 100644 --- a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IfIptoHost.java +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IfIptoHost.java @@ -32,47 +32,100 @@ public interface IfIptoHost { * statically through Northbound APIs. If a binding is unknown, then an ARP * request is initiated immediately to discover the host. * - * @param networkAddress - * IP Address of the Host encapsulated in class InetAddress + * @param id + * IP address and Mac Address combination encapsulated in IHostId + * interface * @return {@link org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector} * Class that contains the Host info such as its MAC address, Switch * ID, port, VLAN. If Host is not found, returns NULL */ - public HostNodeConnector hostFind(InetAddress networkAddress); + public HostNodeConnector hostFind(IHostId id); + + /** + * Applications call this interface methods to determine IP address to MAC + * binding and its connectivity to an OpenFlow switch in term of Node, Port, + * and VLAN. These bindings are learned dynamically as well as can be added + * statically through Northbound APIs. If a binding is unknown, then an ARP + * request is initiated immediately to discover the host. + * + * @param addr + * IP address of the host + * @return {@link org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector} + * Class that contains the Host info such as its MAC address, Switch + * ID, port, VLAN. If Host is not found, returns NULL + */ + public HostNodeConnector hostFind(InetAddress addr); /** * Checks the local Host Database to see if a Host has been learned for a - * given IP address. + * given IP address and Mac combination using the HostId. * - * @param networkAddress - * IP Address of the Host encapsulated in class InetAddress + * @param id + * IP address and Mac Address combination encapsulated in IHostId + * interface + * @return {@link org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector} + * Class that contains the Host info such as its MAC address, Switch + * ID, port, VLAN. If Host is not found, returns NULL + * + */ + public HostNodeConnector hostQuery(IHostId id); + + /** + * Checks the local Host Database to see if a Host has been learned for a + * given IP address and Mac combination using the HostId. + * + * @param addr + * IP address of the Host * @return {@link org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector} * Class that contains the Host info such as its MAC address, Switch * ID, port, VLAN. If Host is not found, returns NULL * */ - public HostNodeConnector hostQuery(InetAddress networkAddress); + public HostNodeConnector hostQuery(InetAddress addr); /** - * Initiates an immediate discovery of the Host for a given IP address. This + * Initiates an immediate discovery of the Host for a given Host id. This * provides for the calling applications to block on the host discovery. * - * @param networkAddress - * IP address encapsulated in InetAddress class + * @param id + * IP address and Mac Address combination encapsulated in IHostId + * interface + * @return Future + * {@link org.opendaylight.controller.hosttracker.HostTrackerCallable} + */ + public Future discoverHost(IHostId id); + + /** + * Initiates an immediate discovery of the Host for a given Host id. This + * provides for the calling applications to block on the host discovery. + * + * @param addr + * IP address of the host * @return Future * {@link org.opendaylight.controller.hosttracker.HostTrackerCallable} */ - public Future discoverHost(InetAddress networkAddress); + public Future discoverHost(InetAddress addr); /** * Returns the Network Hierarchy for a given Host. This API is typically * used by applications like Hadoop for Rack Awareness functionality. * - * @param IP - * address of the Host encapsulated in InetAddress class + * @param id + * IP address and Mac Address combination encapsulated in IHostId + * interface * @return List of String ArrayList containing the Hierarchies. */ - public List> getHostNetworkHierarchy(InetAddress hostAddress); + public List> getHostNetworkHierarchy(IHostId id); + + /** + * Returns the Network Hierarchy for a given Host. This API is typically + * used by applications like Hadoop for Rack Awareness functionality. + * + * @param addr + * IP address of the host + * @return List of String ArrayList containing the Hierarchies. + */ + public List> getHostNetworkHierarchy(InetAddress addr); /** * Returns all the the Hosts either learned dynamically or added statically @@ -124,8 +177,7 @@ public interface IfIptoHost { * @return The status object as described in {@code Status} indicating the * result of this action. */ - public Status addStaticHost(String networkAddress, String dataLayerAddress, - NodeConnector nc, String vlan); + public Status addStaticHost(String networkAddress, String dataLayerAddress, NodeConnector nc, String vlan); /** * Allows the deletion of statically learned Host @@ -135,4 +187,14 @@ public interface IfIptoHost { * result of this action. */ public Status removeStaticHost(String networkAddress); + + /** + * Allows the deletion of statically learned Host + * + * @param networkAddress + * @param macAddress + * @return The status object as described in {@code Status} indicating the + * result of this action. + */ + public Status removeStaticHostUsingIPAndMac(String networkAddress, String macAddress); } diff --git a/opendaylight/hosttracker/implementation/pom.xml b/opendaylight/hosttracker/implementation/pom.xml index 6faf2e9178..258327cca7 100644 --- a/opendaylight/hosttracker/implementation/pom.xml +++ b/opendaylight/hosttracker/implementation/pom.xml @@ -8,7 +8,7 @@ ../../commons/opendaylight hosttracker.implementation - 0.4.1-SNAPSHOT + 0.5.1-SNAPSHOT bundle scm:git:ssh://git.opendaylight.org:29418/controller.git @@ -139,7 +139,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} junit 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 df62c1985a..e1a8ef806a 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 @@ -37,6 +37,10 @@ import org.opendaylight.controller.clustering.services.CacheExistException; import org.opendaylight.controller.clustering.services.ICacheUpdateAware; import org.opendaylight.controller.clustering.services.IClusterContainerServices; import org.opendaylight.controller.clustering.services.IClusterServices; +import org.opendaylight.controller.hosttracker.HostIdFactory; +import org.opendaylight.controller.hosttracker.IHostId; +import org.opendaylight.controller.hosttracker.IPHostId; +import org.opendaylight.controller.hosttracker.IPMacHostId; import org.opendaylight.controller.hosttracker.IfHostListener; import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.IfNewHostNotify; @@ -84,13 +88,25 @@ import org.slf4j.LoggerFactory; * removed the database */ +/*** + * + * HostTracker db key scheme implementation support. Support has been added for + * IP only or IP + MAC scheme as of now. User can use either of the schemes + * based on the configuration done in config.ini file. By default IP only key + * scheme is choosen. The attribute to be set in config.ini is + * hosttracker.keyscheme. It could have a value of 0 or 1 as of now. 0 is for IP + * only scheme. 1 is for IP + MAC scheme. + * + * + */ + public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAware, IInventoryListener, - ITopologyManagerAware, ICacheUpdateAware, CommandProvider { + ITopologyManagerAware, ICacheUpdateAware, CommandProvider { static final String ACTIVE_HOST_CACHE = "hosttracker.ActiveHosts"; static final String INACTIVE_HOST_CACHE = "hosttracker.InactiveHosts"; private static final Logger logger = LoggerFactory.getLogger(HostTracker.class); protected final Set hostFinder = new CopyOnWriteArraySet();; - protected ConcurrentMap hostsDB; + protected ConcurrentMap hostsDB; /* * Following is a list of hosts which have been requested by NB APIs to be * added, but either the switch or the port is not sup, so they will be @@ -109,13 +125,15 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw protected boolean stopping; private static boolean hostRefresh = true; private static int hostRetryCount = 5; + private String keyScheme = null; + private static class ARPPending { - protected InetAddress hostIP; + protected IHostId hostId; protected short sent_count; protected HostTrackerCallable hostTrackerCallable; - public InetAddress getHostIP() { - return hostIP; + public IHostId getHostId() { + return hostId; } public short getSent_count() { @@ -126,8 +144,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return hostTrackerCallable; } - public void setHostIP(InetAddress networkAddr) { - this.hostIP = networkAddr; + public void setHostId(IHostId id) { + this.hostId = id; } public void setSent_count(short count) { @@ -141,7 +159,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw // This list contains the hosts for which ARP requests are being sent // periodically - ConcurrentMap ARPPendingList; + ConcurrentMap ARPPendingList; /* * This list below contains the hosts which were initially in ARPPendingList * above, but ARP response didn't come from there hosts after multiple @@ -158,7 +176,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw * * We can't recover from condition 3 above */ - ConcurrentMap failedARPReqList; + ConcurrentMap failedARPReqList; public HostTracker() { } @@ -175,6 +193,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw /* ARP Refresh Timer to go off every 5 seconds to implement ARP aging */ arpRefreshTimer = new Timer(); arpRefreshTimer.schedule(new ARPRefreshHandler(), 5000, 5000); + keyScheme = HostIdFactory.getScheme(); logger.debug("startUp: Caches created, timers started"); } @@ -204,8 +223,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return; } logger.debug("Retrieving cache for HostTrackerAH"); - hostsDB = (ConcurrentMap) this.clusterContainerService - .getCache(ACTIVE_HOST_CACHE); + hostsDB = (ConcurrentMap) this.clusterContainerService.getCache(ACTIVE_HOST_CACHE); if (hostsDB == null) { logger.error("Cache couldn't be retrieved for HostTracker"); } @@ -220,10 +238,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } public void nonClusterObjectCreate() { - hostsDB = new ConcurrentHashMap(); + hostsDB = new ConcurrentHashMap(); inactiveStaticHosts = new ConcurrentHashMap(); - ARPPendingList = new ConcurrentHashMap(); - failedARPReqList = new ConcurrentHashMap(); + ARPPendingList = new ConcurrentHashMap(); + failedARPReqList = new ConcurrentHashMap(); } public void shutDown() { @@ -262,66 +280,72 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } private boolean hostExists(HostNodeConnector host) { - HostNodeConnector lhost = hostsDB.get(host.getNetworkAddress()); + IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress()); + HostNodeConnector lhost = hostsDB.get(id); return host.equals(lhost); } - private HostNodeConnector getHostFromOnActiveDB(InetAddress networkAddress) { - return hostsDB.get(networkAddress); + private HostNodeConnector getHostFromOnActiveDB(IHostId id) { + return hostsDB.get(id); } - private Entry getHostFromInactiveDB(InetAddress networkAddress) { + private Entry getHostFromInactiveDB(IHostId id) { for (Entry entry : inactiveStaticHosts.entrySet()) { - if (entry.getValue().equalsByIP(networkAddress)) { - logger.debug("getHostFromInactiveDB(): Inactive Host found for IP:{} ", networkAddress.getHostAddress()); + HostNodeConnector hnc = entry.getValue(); + IHostId cmpId = HostIdFactory.create(hnc.getNetworkAddress(), hnc.getDataLayerAddress()); + if (cmpId.equals(id)) { + logger.debug("getHostFromInactiveDB(): Inactive Host found for ID:{} ", decodeIPFromId(id)); return entry; } } - logger.debug("getHostFromInactiveDB() Inactive Host Not found for IP: {}", networkAddress.getHostAddress()); + logger.debug("getHostFromInactiveDB() Inactive Host Not found for ID: {}", decodeIPFromId(id)); return null; } - private void removeHostFromInactiveDB(InetAddress networkAddress) { + private void removeHostFromInactiveDB(IHostId id) { NodeConnector nodeConnector = null; for (Entry entry : inactiveStaticHosts.entrySet()) { - if (entry.getValue().equalsByIP(networkAddress)) { + HostNodeConnector hnc = entry.getValue(); + IHostId cmpId = HostIdFactory.create(hnc.getNetworkAddress(), hnc.getDataLayerAddress()); + if (cmpId.equals(id)) { nodeConnector = entry.getKey(); break; } } if (nodeConnector != null) { inactiveStaticHosts.remove(nodeConnector); - logger.debug("removeHostFromInactiveDB(): Host Removed for IP: {}", networkAddress.getHostAddress()); + logger.debug("removeHostFromInactiveDB(): Host Removed for IP: {}", decodeIPFromId(id)); return; } - logger.debug("removeHostFromInactiveDB(): Host Not found for IP: {}", networkAddress.getHostAddress()); + logger.debug("removeHostFromInactiveDB(): Host Not found for IP: {}", decodeIPFromId(id)); } protected boolean hostMoved(HostNodeConnector host) { - if (hostQuery(host.getNetworkAddress()) != null) { + IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress()); + if (hostQuery(id) != null) { return true; } return false; } @Override - public HostNodeConnector hostQuery(InetAddress networkAddress) { - return hostsDB.get(networkAddress); + public HostNodeConnector hostQuery(IHostId id) { + return hostsDB.get(id); } @Override - public Future discoverHost(InetAddress networkAddress) { + public Future discoverHost(IHostId id) { if (executor == null) { logger.debug("discoverHost: Null executor"); return null; } - Callable worker = new HostTrackerCallable(this, networkAddress); + Callable worker = new HostTrackerCallable(this, id); Future submit = executor.submit(worker); return submit; } @Override - public HostNodeConnector hostFind(InetAddress networkAddress) { + public HostNodeConnector hostFind(IHostId id) { /* * Sometimes at boot with containers configured in the startup we hit * this path (from TIF) when hostFinder has not been set yet Caller @@ -333,21 +357,21 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return null; } - HostNodeConnector host = hostQuery(networkAddress); + HostNodeConnector host = hostQuery(id); if (host != null) { - logger.debug("hostFind(): Host found for IP: {}", networkAddress.getHostAddress()); + logger.debug("hostFind(): Host found for IP: {}", id); return host; } /* 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()); + addToARPPendingList(id); + logger.debug("hostFind(): Host Not Found for IP: {}, Inititated Host Discovery ...", id); /* host is not found, initiate a discovery */ for (IHostFinder hf : hostFinder) { - hf.find(networkAddress); + InetAddress addr = decodeIPFromId(id); + hf.find(addr); } return null; } @@ -361,7 +385,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw @Override public Set getActiveStaticHosts() { Set list = new HashSet(); - for (Entry entry : hostsDB.entrySet()) { + for (Entry entry : hostsDB.entrySet()) { HostNodeConnector host = entry.getValue(); if (host.isStaticHost()) { list.add(host); @@ -376,31 +400,32 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return list; } - private void addToARPPendingList(InetAddress networkAddr) { + private void addToARPPendingList(IHostId id) { ARPPending arphost = new ARPPending(); - arphost.setHostIP(networkAddr); + arphost.setHostId(id); arphost.setSent_count((short) 1); - ARPPendingList.put(networkAddr, arphost); - logger.debug("Host Added to ARPPending List, IP: {}", networkAddr); + ARPPendingList.put(id, arphost); + logger.debug("Host Added to ARPPending List, IP: {}", decodeIPFromId(id)); + } - public void setCallableOnPendingARP(InetAddress networkAddr, HostTrackerCallable callable) { + public void setCallableOnPendingARP(IHostId id, HostTrackerCallable callable) { ARPPending arphost; - for (Entry entry : ARPPendingList.entrySet()) { + for (Entry entry : ARPPendingList.entrySet()) { arphost = entry.getValue(); - if (arphost.getHostIP().equals(networkAddr)) { + if (arphost.getHostId().equals(id)) { arphost.setHostTrackerCallable(callable); } } } - private void processPendingARPReqs(InetAddress networkAddr) { + private void processPendingARPReqs(IHostId id) { ARPPending arphost; - if ((arphost = ARPPendingList.remove(networkAddr)) != null) { + if ((arphost = ARPPendingList.remove(id)) != null) { // Remove the arphost from ARPPendingList as it has been learned now - logger.debug("Host Removed from ARPPending List, IP: {}", networkAddr); + logger.debug("Host Removed from ARPPending List, IP: {}", id); HostTrackerCallable htCallable = arphost.getHostTrackerCallable(); if (htCallable != null) { htCallable.wakeup(); @@ -412,26 +437,27 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw * It could have been a host from the FailedARPReqList */ - if (failedARPReqList.containsKey(networkAddr)) { - failedARPReqList.remove(networkAddr); - logger.debug("Host Removed from FailedARPReqList List, IP: {}", networkAddr); + if (failedARPReqList.containsKey(id)) { + failedARPReqList.remove(id); + logger.debug("Host Removed from FailedARPReqList List, IP: {}", decodeIPFromId(id)); } } // Learn a new Host private void learnNewHost(HostNodeConnector host) { + IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress()); host.initArpSendCountDown(); - HostNodeConnector rHost = hostsDB.putIfAbsent(host.getNetworkAddress(), host); + HostNodeConnector rHost = hostsDB.putIfAbsent(id, host); if (rHost != null) { // Another host is already learned for this IP address, replace it - replaceHost(host.getNetworkAddress(), rHost, host); + replaceHost(id, rHost, host); } else { logger.debug("New Host Learned: MAC: {} IP: {}", HexEncode.bytesToHexString(host .getDataLayerAddressBytes()), host.getNetworkAddress().getHostAddress()); } } - private void replaceHost(InetAddress networkAddr, HostNodeConnector removedHost, HostNodeConnector newHost) { + private void replaceHost(IHostId id, HostNodeConnector removedHost, HostNodeConnector newHost) { // Ignore ARP messages from internal nodes NodeConnector newHostNc = newHost.getnodeConnector(); boolean newHostIsInternal = topologyManager.isInternal(newHostNc); @@ -441,7 +467,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw newHost.initArpSendCountDown(); - if (hostsDB.replace(networkAddr, removedHost, newHost)) { + if (hostsDB.replace(id, 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: {}", @@ -453,25 +479,25 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw /* * Host replacement has failed, do the recovery */ - hostsDB.put(networkAddr, newHost); + hostsDB.put(id, newHost); logger.error("Host replacement failed. Overwrite the host. Repalced Host: {}, New Host: {}", removedHost, newHost); } notifyHostLearnedOrRemoved(removedHost, false); notifyHostLearnedOrRemoved(newHost, true); if (!newHost.isStaticHost()) { - processPendingARPReqs(networkAddr); + processPendingARPReqs(id); } } // Remove known Host - private void removeKnownHost(InetAddress key) { + private void removeKnownHost(IHostId key) { HostNodeConnector host = hostsDB.get(key); if (host != null) { logger.debug("Removing Host: IP:{}", host.getNetworkAddress().getHostAddress()); hostsDB.remove(key); } else { - logger.error("removeKnownHost(): Host for IP address {} not found in hostsDB", key.getHostAddress()); + logger.error("removeKnownHost(): Host for IP address {} not found in hostsDB", decodeIPFromId(key)); } } @@ -487,7 +513,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw public void run() { HostNodeConnector removedHost = null; InetAddress networkAddr = host.getNetworkAddress(); - + IHostId id = HostIdFactory.create(networkAddr, host.getDataLayerAddress()); /* Check for Host Move case */ if (hostMoved(host)) { /* @@ -496,9 +522,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw * location parameters with new information, and notify the * applications listening to host move. */ - removedHost = hostsDB.get(networkAddr); + + removedHost = hostsDB.get(id); if (removedHost != null) { - replaceHost(networkAddr, removedHost, host); + replaceHost(id, removedHost, host); return; } else { logger.error("Host to be removed not found in hostsDB"); @@ -509,7 +536,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw learnNewHost(host); /* check if there is an outstanding request for this host */ - processPendingARPReqs(networkAddr); + processPendingARPReqs(id); notifyHostLearnedOrRemoved(host, true); } } @@ -519,10 +546,13 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw logger.debug("Received for Host: IP {}, MAC {}, {}", host.getNetworkAddress().getHostAddress(), HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host); if (hostExists(host)) { - HostNodeConnector existinghost = hostsDB.get(host.getNetworkAddress()); + IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress()); + HostNodeConnector existinghost = hostsDB.get(id); existinghost.initArpSendCountDown(); // Update the host - hostsDB.put(host.getNetworkAddress(), existinghost); + + hostsDB.put(id, existinghost); + logger.debug("hostListener returned without adding the host"); return; } new NotifyHostThread(host).start(); @@ -720,8 +750,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw * Switch-Ids as String). */ @Override - public List> getHostNetworkHierarchy(InetAddress hostAddress) { - HostNodeConnector host = hostQuery(hostAddress); + public List> getHostNetworkHierarchy(IHostId id) { + HostNodeConnector host = hostQuery(id); if (host == null) { return null; } @@ -903,16 +933,16 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw public void subnetNotify(Subnet sub, boolean add) { logger.debug("Received subnet notification: {} add={}", sub, add); if (add) { - for (Entry entry : failedARPReqList.entrySet()) { + for (Entry entry : failedARPReqList.entrySet()) { ARPPending arphost; arphost = entry.getValue(); 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()); + logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", decodeIPFromId(arphost.getHostId())); for (IHostFinder hf : hostFinder) { - hf.find(arphost.getHostIP()); + hf.find(decodeIPFromId(arphost.getHostId())); } } } @@ -928,14 +958,14 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw /* This routine runs every 4 seconds */ logger.trace("Number of Entries in ARP Pending/Failed Lists: ARPPendingList = {}, failedARPReqList = {}", ARPPendingList.size(), failedARPReqList.size()); - for (Entry entry : ARPPendingList.entrySet()) { + for (Entry entry : ARPPendingList.entrySet()) { arphost = entry.getValue(); - if (hostsDB.containsKey(arphost.getHostIP())) { + if (hostsDB.containsKey(arphost.getHostId())) { // this host is already learned, shouldn't be in // ARPPendingList // Remove it and continue - logger.warn("Learned Host {} found in ARPPendingList", arphost.getHostIP()); + logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId())); ARPPendingList.remove(entry.getKey()); continue; } @@ -950,10 +980,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw continue; } for (IHostFinder hf : hostFinder) { - hf.find(arphost.getHostIP()); + hf.find(decodeIPFromId(arphost.getHostId())); } arphost.sent_count++; - logger.debug("ARP Sent from ARPPending List, IP: {}", arphost.getHostIP().getHostAddress()); + logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId())); } else if (arphost.getSent_count() >= hostRetryCount) { /* * ARP requests have been sent without receiving a reply, @@ -961,12 +991,12 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw */ ARPPendingList.remove(entry.getKey()); logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}", - arphost.getHostIP().getHostAddress()); + decodeIPFromId(arphost.getHostId())); /* * Add this host to a different list which will be processed * on link up events */ - logger.debug("Adding the host to FailedARPReqList IP: {}", arphost.getHostIP().getHostAddress()); + logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId())); failedARPReqList.put(entry.getKey(), arphost); } else { @@ -996,7 +1026,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:"); return; } - for (Entry entry : hostsDB.entrySet()) { + for (Entry entry : hostsDB.entrySet()) { HostNodeConnector host = entry.getValue(); if (host.isStaticHost()) { /* this host was learned via API3, don't age it out */ @@ -1073,6 +1103,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw HostNodeConnector host = null; try { host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan); + IHostId id = HostIdFactory.create(networkAddr, new EthernetAddress(dataLayerAddress)); if (hostExists(host)) { // This host is already learned either via ARP or through a // northbound request @@ -1081,7 +1112,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return new Status(StatusCode.SUCCESS); } - if (hostsDB.get(networkAddr) != null) { + if (hostsDB.get(id) != null) { // There is already a host with this IP address (but behind // a different (switch, port, vlan) tuple. Return an error return new Status(StatusCode.CONFLICT, "Host with this IP already exists."); @@ -1101,7 +1132,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw */ if (switchManager.isNodeConnectorEnabled(nc)) { learnNewHost(host); - processPendingARPReqs(networkAddr); + processPendingARPReqs(id); notifyHostLearnedOrRemoved(host, true); } else { inactiveStaticHosts.put(nc, host); @@ -1152,8 +1183,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return new Status(StatusCode.BADREQUEST, "Host already exists"); } + IHostId id = HostIdFactory.create(networkAddr, new EthernetAddress(dataLayerAddress)); + if ((tobeUpdatedHost = hostsDB.get(networkAddr)) != null) { - if (hostsDB.replace(networkAddr, tobeUpdatedHost, host)) { + if (hostsDB.replace(id, tobeUpdatedHost, host)) { logger.debug("Host replaced from hostsDB. Old host: {} New Host: {}", tobeUpdatedHost, host); notifyHostLearnedOrRemoved(tobeUpdatedHost, false); notifyHostLearnedOrRemoved(host, true); @@ -1199,9 +1232,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw * otherwise */ - public Status removeStaticHostReq(InetAddress networkAddress) { + public Status removeStaticHostReq(InetAddress networkAddress, DataLinkAddress mac) { // Check if host is in active hosts database - HostNodeConnector host = getHostFromOnActiveDB(networkAddress); + IHostId id = HostIdFactory.create(networkAddress, mac); + HostNodeConnector host = getHostFromOnActiveDB(id); if (host != null) { // Validation check if (!host.isStaticHost()) { @@ -1209,19 +1243,19 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } // Remove and notify notifyHostLearnedOrRemoved(host, false); - removeKnownHost(networkAddress); + removeKnownHost(id); return new Status(StatusCode.SUCCESS, null); } // Check if host is in inactive hosts database - Entry entry = getHostFromInactiveDB(networkAddress); + Entry entry = getHostFromInactiveDB(id); if (entry != null) { host = entry.getValue(); // Validation check if (!host.isStaticHost()) { return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static"); } - this.removeHostFromInactiveDB(networkAddress); + this.removeHostFromInactiveDB(id); return new Status(StatusCode.SUCCESS, null); } @@ -1243,7 +1277,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw switch (type) { case REMOVED: logger.debug("Received removed node {}", node); - for (Entry entry : hostsDB.entrySet()) { + for (Entry entry : hostsDB.entrySet()) { HostNodeConnector host = entry.getValue(); if (host.getnodeconnectorNode().equals(node)) { logger.debug("Node: {} is down, remove from Hosts_DB", node); @@ -1313,23 +1347,65 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw @Override public Status removeStaticHost(String networkAddress) { try { + if ((keyScheme != null) && (!keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) { + return new Status(StatusCode.NOTALLOWED, "Host DB Key scheme used is not IP only scheme."); + } InetAddress address = InetAddress.getByName(networkAddress); - return removeStaticHostReq(address); + return removeStaticHostReq(address, null); } catch (UnknownHostException e) { logger.debug("Invalid IP Address when trying to remove host", e); return new Status(StatusCode.BADREQUEST, "Invalid IP Address when trying to remove host"); } } + @Override + public Status removeStaticHostUsingIPAndMac(String networkAddress, String macAddress) { + try { + if ((keyScheme != null) && (keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) { + return new Status(StatusCode.NOTALLOWED, "Host DB Key scheme used is not IP only scheme."); + } + InetAddress address = InetAddress.getByName(networkAddress); + DataLinkAddress mac = new EthernetAddress(HexEncode.bytesFromHexString(macAddress)); + return removeStaticHostReq(address, mac); + } catch (UnknownHostException e) { + logger.debug("Invalid IP Address when trying to remove host", e); + return new Status(StatusCode.BADREQUEST, "Invalid IP Address when trying to remove host"); + } catch (ConstructionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return new Status(StatusCode.BADREQUEST, "Invalid Input parameters have been passed."); + } + } + + private InetAddress decodeIPFromId(IHostId id) { + if ((keyScheme != null) && (keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) { + IPHostId ipId = (IPHostId) id; + return (ipId.getIpAddress()); + } else if ((keyScheme != null) && (keyScheme.equals(HostIdFactory.IP_MAC_KEY_SCHEME))) { + IPMacHostId ipMacId = (IPMacHostId) id; + return (ipMacId.getIpAddress()); + } + return null; + } + + private DataLinkAddress decodeMacFromId(IHostId id) { + if ((keyScheme != null) && (!keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) { + IPMacHostId ipMacId = (IPMacHostId) id; + return (ipMacId.getMacAddr()); + } + + return null; + } + private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) { ARPPending arphost; HostNodeConnector host = null; logger.trace("handleNodeConnectorStatusUp {}", nodeConnector); - for (Entry entry : failedARPReqList.entrySet()) { + for (Entry entry : failedARPReqList.entrySet()) { arphost = entry.getValue(); - logger.trace("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress()); + logger.trace("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostId()); 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", @@ -1341,13 +1417,14 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw // Use hostFinder's "probe" method try { byte[] dataLayerAddress = NetUtils.getBroadcastMACAddr(); - host = new HostNodeConnector(dataLayerAddress, arphost.getHostIP(), nodeConnector, (short) 0); + host = new HostNodeConnector(dataLayerAddress, decodeIPFromId(arphost.getHostId()), nodeConnector, + (short) 0); for (IHostFinder hf : hostFinder) { hf.probe(host); } } catch (ConstructionException e) { logger.debug("HostNodeConnector couldn't be created for Host: {}, NodeConnector: {}", - arphost.getHostIP(), nodeConnector); + arphost.getHostId(), nodeConnector); logger.error("", e); } } @@ -1356,7 +1433,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw if (host != null) { inactiveStaticHosts.remove(nodeConnector); learnNewHost(host); - processPendingARPReqs(host.getNetworkAddress()); + IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress()); + processPendingARPReqs(id); notifyHostLearnedOrRemoved(host, true); } } @@ -1364,7 +1442,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) { logger.trace("handleNodeConnectorStatusDown {}", nodeConnector); - for (Entry entry : hostsDB.entrySet()) { + for (Entry entry : hostsDB.entrySet()) { HostNodeConnector host = entry.getValue(); if (host.getnodeConnector().equals(nodeConnector)) { logger.debug(" NodeConnector: {} is down, remove from Hosts_DB", nodeConnector); @@ -1420,6 +1498,8 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw this.containerName = ""; } startUp(); + + logger.debug("key Scheme in hosttracker is {}", keyScheme); } /** @@ -1467,7 +1547,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } @Override - public void entryCreated(InetAddress key, String cacheName, boolean originLocal) { + public void entryCreated(IHostId key, String cacheName, boolean originLocal) { if (originLocal) { return; } @@ -1475,11 +1555,11 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } @Override - public void entryUpdated(InetAddress key, HostNodeConnector new_value, String cacheName, boolean originLocal) { + public void entryUpdated(IHostId key, HostNodeConnector new_value, String cacheName, boolean originLocal) { } @Override - public void entryDeleted(InetAddress key, String cacheName, boolean originLocal) { + public void entryDeleted(IHostId key, String cacheName, boolean originLocal) { } private void registerWithOSGIConsole() { @@ -1494,17 +1574,41 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw public void _dumpPendingARPReqList(CommandInterpreter ci) { ARPPending arphost; - for (Entry entry : ARPPendingList.entrySet()) { + for (Entry entry : ARPPendingList.entrySet()) { arphost = entry.getValue(); - ci.println(arphost.getHostIP().toString()); + ci.println(arphost.getHostId().toString()); } } public void _dumpFailedARPReqList(CommandInterpreter ci) { ARPPending arphost; - for (Entry entry : failedARPReqList.entrySet()) { + for (Entry entry : failedARPReqList.entrySet()) { arphost = entry.getValue(); - ci.println(arphost.getHostIP().toString()); + ci.println(arphost.getHostId().toString()); } } + + @Override + public HostNodeConnector hostFind(InetAddress addr) { + IHostId id = HostIdFactory.create(addr, null); + return (hostFind(id)); + } + + @Override + public HostNodeConnector hostQuery(InetAddress addr) { + IHostId id = HostIdFactory.create(addr, null); + return (hostQuery(id)); + } + + @Override + public Future discoverHost(InetAddress addr) { + IHostId id = HostIdFactory.create(addr, null); + return discoverHost(id); + } + + @Override + public List> getHostNetworkHierarchy(InetAddress addr) { + IHostId id = HostIdFactory.create(addr, null); + return getHostNetworkHierarchy(id); + } } diff --git a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTrackerCallable.java b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTrackerCallable.java index 303308270d..a1d29dd27f 100644 --- a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTrackerCallable.java +++ b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTrackerCallable.java @@ -18,19 +18,24 @@ package org.opendaylight.controller.hosttracker.internal; * find a host in HostTracker's database and want to discover the host * in the same thread without being called by a callback function. */ -import java.net.InetAddress; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; +import org.opendaylight.controller.hosttracker.IHostId; import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; +/** + * + * + */ public class HostTrackerCallable implements Callable { - InetAddress trackedHost; + //host id which could be ip or a combination of ip + mac based on the scheme chosen. + IHostId trackedHost; HostTracker hostTracker; protected CountDownLatch latch; - public HostTrackerCallable(HostTracker tracker, InetAddress inet) { + public HostTrackerCallable(HostTracker tracker, IHostId inet) { trackedHost = inet; hostTracker = tracker; latch = new CountDownLatch(1); diff --git a/opendaylight/hosttracker/implementation/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerTest.java b/opendaylight/hosttracker/implementation/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerTest.java index dc15f96f6e..d7c60e67a9 100644 --- a/opendaylight/hosttracker/implementation/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerTest.java +++ b/opendaylight/hosttracker/implementation/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerTest.java @@ -10,10 +10,13 @@ package org.opendaylight.controller.hosttracker.internal; import java.net.InetAddress; import java.net.UnknownHostException; + import junit.framework.TestCase; import org.junit.Assert; import org.junit.Test; +import org.opendaylight.controller.hosttracker.IHostId; +import org.opendaylight.controller.hosttracker.IPHostId; public class HostTrackerTest extends TestCase { @@ -25,10 +28,11 @@ public class HostTrackerTest extends TestCase { Assert.assertFalse(hostTracker == null); InetAddress hostIP = InetAddress.getByName("192.168.0.8"); + IHostId id = IPHostId.fromIP(hostIP); HostTrackerCallable htCallable = new HostTrackerCallable(hostTracker, - hostIP); - Assert.assertTrue(htCallable.trackedHost.equals(hostIP)); + id); + Assert.assertTrue(htCallable.trackedHost.equals(id)); Assert.assertTrue(htCallable.hostTracker.equals(hostTracker)); long count = htCallable.latch.getCount(); @@ -43,9 +47,11 @@ public class HostTrackerTest extends TestCase { Assert.assertFalse(hostTracker == null); InetAddress hostIP_1 = InetAddress.getByName("192.168.0.8"); + IHostId id1 = IPHostId.fromIP(hostIP_1); InetAddress hostIP_2 = InetAddress.getByName("192.168.0.18"); - hostTracker.discoverHost(hostIP_1); - hostTracker.discoverHost(hostIP_2); + IHostId id2 = IPHostId.fromIP(hostIP_2); + hostTracker.discoverHost(id1); + hostTracker.discoverHost(id2); hostTracker.nonClusterObjectCreate(); } diff --git a/opendaylight/hosttracker/integrationtest/pom.xml b/opendaylight/hosttracker/integrationtest/pom.xml index 7274ef8e55..8f4163d686 100644 --- a/opendaylight/hosttracker/integrationtest/pom.xml +++ b/opendaylight/hosttracker/integrationtest/pom.xml @@ -15,18 +15,18 @@ hosttracker.integrationtest - 0.4.1-SNAPSHOT + 0.5.1-SNAPSHOT org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller hosttracker.implementation - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller @@ -53,7 +53,7 @@ org.opendaylight.controller arphandler - 0.4.1-SNAPSHOT + ${arphandler.version} org.opendaylight.controller diff --git a/opendaylight/hosttracker/integrationtest/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerIT.java b/opendaylight/hosttracker/integrationtest/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerIT.java index cea8af009f..a454eb97e1 100644 --- a/opendaylight/hosttracker/integrationtest/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerIT.java +++ b/opendaylight/hosttracker/integrationtest/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerIT.java @@ -27,6 +27,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.opendaylight.controller.hosttracker.IHostId; +import org.opendaylight.controller.hosttracker.IPHostId; import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; import org.opendaylight.controller.sal.core.Node; @@ -45,6 +47,7 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + //import org.opendaylight.controller.hosttracker.*; @RunWith(PaxExam.class) @@ -56,6 +59,7 @@ public class HostTrackerIT { private IfIptoHost hosttracker = null; private IInventoryListener invtoryListener = null; + // Configure the OSGi container @Configuration public Option[] config() { @@ -218,7 +222,6 @@ public class HostTrackerIT { st = this.hosttracker.addStaticHost("192.168.0.13", "11:22:33:44:55:77", nc1_2, "0"); Assert.assertFalse(st.isSuccess()); - this.invtoryListener.notifyNodeConnector(nc1_1, UpdateType.ADDED, null); // check all host list @@ -257,12 +260,15 @@ public class HostTrackerIT { Status st = this.hosttracker.addStaticHost("192.168.0.8", "11:22:33:44:55:66", nc1_1, null); st = this.hosttracker.addStaticHost("192.168.0.13", "11:22:33:44:55:77", nc1_2, ""); - HostNodeConnector hnc_1 = this.hosttracker.hostFind(InetAddress.getByName("192.168.0.8")); + IHostId id1 = IPHostId.fromIP(InetAddress.getByName("192.168.0.8")); + HostNodeConnector hnc_1 = this.hosttracker.hostFind(id1); assertNull(hnc_1); this.invtoryListener.notifyNodeConnector(nc1_1, UpdateType.ADDED, null); - hnc_1 = this.hosttracker.hostFind(InetAddress.getByName("192.168.0.8")); + IHostId id2 = IPHostId.fromIP(InetAddress.getByName("192.168.0.8")); + hnc_1 = this.hosttracker.hostFind(id2); + assertNotNull(hnc_1); } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java index 82db78e7b9..2ffe0ecd87 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/FlowConsumerImpl.java @@ -71,7 +71,7 @@ public class FlowConsumerImpl implements IForwardingRulesManager { private IContainer container; private static final String NAMEREGEX = "^[a-zA-Z0-9]+$"; private static ConcurrentMap staticFlows; - private static ConcurrentMap staticFlowsOrdinal; + private static ConcurrentMap staticFlowsOrdinal = new ConcurrentHashMap(); /* * Inactive flow list. This is for the global instance of FRM It will * contain all the flow entries which were installed on the global container @@ -86,7 +86,8 @@ public class FlowConsumerImpl implements IForwardingRulesManager { private boolean inContainerMode; // being used by global instance only public FlowConsumerImpl() { - InstanceIdentifier path = InstanceIdentifier.builder().node(Flows.class).toInstance(); + InstanceIdentifier path = InstanceIdentifier.builder(Flows.class).child(Flow.class) + .toInstance(); flowService = FRMConsumerImpl.getProviderSession().getRpcService(SalFlowService.class); if (null == flowService) { @@ -499,14 +500,13 @@ public class FlowConsumerImpl implements IForwardingRulesManager { @Override public void onNodeErrorNotification(NodeErrorNotification notification) { // TODO Auto-generated method stub - + } @Override - public void onNodeExperimenterErrorNotification( - NodeExperimenterErrorNotification notification) { + public void onNodeExperimenterErrorNotification(NodeExperimenterErrorNotification notification) { // TODO Auto-generated method stub - + }; } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java index 8595491016..851e7d9b26 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java @@ -68,8 +68,8 @@ public class GroupConsumerImpl implements IForwardingRulesManager { public GroupConsumerImpl() { - InstanceIdentifier path = InstanceIdentifier.builder().node(Groups.class) - .node(Group.class).toInstance(); + InstanceIdentifier path = InstanceIdentifier.builder(Groups.class).child(Group.class) + .toInstance(); groupService = FRMConsumerImpl.getProviderSession().getRpcService(SalGroupService.class); clusterGroupContainerService = FRMConsumerImpl.getClusterContainerService(); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java index 7f7db3ba58..bd0ceb3fea 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java @@ -66,8 +66,8 @@ public class MeterConsumerImpl implements IForwardingRulesManager { private IContainer container; public MeterConsumerImpl() { - InstanceIdentifier path = InstanceIdentifier.builder().node(Meters.class) - .node(Meter.class).toInstance(); + InstanceIdentifier path = InstanceIdentifier.builder(Meters.class).child(Meter.class) + .toInstance(); meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class); clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService(); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/TableFeaturesConsumerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/TableFeaturesConsumerImpl.java new file mode 100644 index 0000000000..30556e4714 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/TableFeaturesConsumerImpl.java @@ -0,0 +1,192 @@ +package org.opendaylight.controller.forwardingrulesmanager.consumer.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.opendaylight.controller.clustering.services.IClusterContainerServices; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.core.IContainer; +import org.opendaylight.controller.sal.utils.ServiceHelper; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.Tables; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.config.rev131024.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.UpdateTableInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.table.update.UpdatedTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TableFeaturesConsumerImpl { + protected static final Logger logger = LoggerFactory.getLogger(TableFeaturesConsumerImpl.class); + private SalTableService tableService; + private TableDataCommitHandler commitHandler; + private final IClusterContainerServices clusterContainerService = null; + private IContainer container; + private static final String NAMEREGEX = "^[a-zA-Z0-9]+$"; + private boolean inContainerMode; // being used by global instance only + + public TableFeaturesConsumerImpl() { + InstanceIdentifier path = InstanceIdentifier.builder(Tables.class).child(Table.class) + .toInstance(); + tableService = FRMConsumerImpl.getProviderSession().getRpcService(SalTableService.class); + + if (null == tableService) { + logger.error("Consumer SAL Service is down or NULL. FRM may not function as intended"); + System.out.println("Consumer SAL Service is down or NULL."); + return; + } + + System.out.println("-------------------------------------------------------------------"); + commitHandler = new TableDataCommitHandler(); + FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler); + container = (IContainer) ServiceHelper.getGlobalInstance(IContainer.class, this); + } + + /** + * Updates TableFeatures to the southbound plugin and our internal database + * + * @param path + * @param dataObject + */ + private void updateTableFeatures(InstanceIdentifier path, TableFeatures dataObject) { + + UpdateTableInputBuilder input = new UpdateTableInputBuilder(); + UpdatedTableBuilder updatedtablebuilder = new UpdatedTableBuilder(); + updatedtablebuilder.fieldsFrom(dataObject); + List features = updatedtablebuilder.build().getTableFeatures(); + for (TableFeatures feature : features) { + if (feature != null && feature.getMaxEntries() != null) { + logger.error("Max Entries field is read-only, cannot be changed"); + return; + } + } + input.setUpdatedTable(updatedtablebuilder.build()); + + // We send table feature update request to the sounthbound plugin + tableService.updateTable(input.build()); + } + + @SuppressWarnings("unchecked") + private void commitToPlugin(internalTransaction transaction) { + + for (@SuppressWarnings("unused") + Entry, TableFeatures> entry : transaction.updates.entrySet()) { + System.out.println("Coming update cc in TableDatacommitHandler"); + updateTableFeatures(entry.getKey(), entry.getValue()); + } + + } + + private final class TableDataCommitHandler implements DataCommitHandler, DataObject> { + + @SuppressWarnings("unchecked") + @Override + public DataCommitTransaction requestCommit(DataModification, DataObject> modification) { + // We should verify transaction + System.out.println("Coming in TableFeaturesDatacommitHandler"); + internalTransaction transaction = new internalTransaction(modification); + transaction.prepareUpdate(); + return transaction; + } + } + + private final class internalTransaction implements DataCommitTransaction, DataObject> { + + private final DataModification, DataObject> modification; + + @Override + public DataModification, DataObject> getModification() { + return modification; + } + + public internalTransaction(DataModification, DataObject> modification) { + this.modification = modification; + } + + Map, TableFeatures> updates = new HashMap<>(); + + /** + * We create a plan which table features will be updated. + * + */ + void prepareUpdate() { + + Set, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet(); + for (Entry, DataObject> entry : puts) { + + // validating the DataObject + + Status status = validate(container, (TableFeatures) entry); + if (!status.isSuccess()) { + logger.warn("Invalid Configuration for table features The failure is {}", entry, + status.getDescription()); + String error = "Invalid Configuration (" + status.getDescription() + ")"; + logger.error(error); + return; + } + if (entry.getValue() instanceof TableFeatures) { + TableFeatures tablefeatures = (TableFeatures) entry.getValue(); + preparePutEntry(entry.getKey(), tablefeatures); + } + + } + } + + private void preparePutEntry(InstanceIdentifier key, TableFeatures tablefeatures) { + if (tablefeatures != null) { + // Updating the Map + System.out.println("Coming update in TableFeaturesDatacommitHandler"); + updates.put(key, tablefeatures); + } + } + + /** + * We are OK to go with execution of plan + * + */ + @Override + public RpcResult finish() throws IllegalStateException { + + commitToPlugin(this); + // We return true if internal transaction is successful. + // return Rpcs.getRpcResult(true, null, Collections.emptySet()); + return Rpcs.getRpcResult(true, null, null); + } + + /** + * + * We should rollback our preparation + * + */ + @Override + public RpcResult rollback() throws IllegalStateException { + // NOOP - we did not modified any internal state during + // requestCommit phase + // return Rpcs.getRpcResult(true, null, Collections.emptySet()); + return Rpcs.getRpcResult(true, null, null); + + } + + public Status validate(IContainer container, TableFeatures dataObject) { + + String tablename = dataObject.getName(); + if (tablename == null || tablename.trim().isEmpty() || !tablename.matches(NAMEREGEX) + || tablename.length() != 32) { + return new Status(StatusCode.BADREQUEST, "Invalid table name"); + } + + return new Status(StatusCode.SUCCESS); + } + } +} diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang index 4b50c0ee72..67c6933cc7 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/flow-types.yang @@ -72,6 +72,15 @@ module opendaylight-flow-types { bit SEND_FLOW_REM; } } + + typedef removed_reason_flags { + type bits { + bit IDLE_TIMEOUT; + bit HARD_TIMEOUT; + bit DELETE; + bit GROUP_DELETE; + } + } grouping generic_flow_attributes { leaf priority { @@ -185,6 +194,10 @@ module opendaylight-flow-types { grouping flow-mod-removed { uses generic_flow_attributes; + leaf removed_reason { + type removed_reason_flags; + } + leaf duration_nsec { type uint32; } @@ -192,22 +205,15 @@ module opendaylight-flow-types { leaf duration_sec { type uint32; } - - leaf idle_timeout { - type uint16; - } - - leaf hard_timeout { - type uint16; - } - + leaf packet_count { type uint64; } - + leaf byte_count { type uint64; } + container match { uses match:match; } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang index 97ca8b3c71..25e8e7aa57 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/group-types.yang @@ -18,13 +18,23 @@ module opendaylight-group-types { leaf group-type { type enumeration { enum group-all; - enum group_select; - enum group_indirect; - enum group_ff; + enum group-select; + enum group-indirect; + enum group-ff; } } } + typedef group-capabilities { + type enumeration { + enum select-weight; + enum select-liveness; + enum chaining; + enum chaining-checks; + } + } + + grouping group { uses group-types; @@ -119,14 +129,21 @@ module opendaylight-group-types { } grouping group-features { - uses group-types; + leaf types { + type bits { + bit group-all; + bit group-select; + bit group-indirect; + bit group-ff; + } + } leaf capabilities { - type enumeration { - enum select-weight; - enum select-liveness; - enum chaining; - enum chaining-checks; + type bits { + bit select-weight; + bit select-liveness; + bit chaining; + bit chaining-checks; } } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang new file mode 100644 index 0000000000..57a92378c0 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/queue-types.yang @@ -0,0 +1,77 @@ +module opendaylight-queue-types { + namespace "urn:opendaylight:flow:types:queue"; + prefix queue-types; + + import ietf-inet-types {prefix inet; revision-date "2010-09-24";} + import ietf-yang-types {prefix yang; revision-date "2010-09-24";} + + revision "2013-09-25" { + description "Initial revision of Queue Inventory model"; + } + + typedef queue-properties { + type enumeration { + enum min_rate; + enum max_rate; + } + } + + + grouping common-queue { + + leaf property { + type uint16; + description "One of OFPQT_."; + } + + } + + + grouping queue-prop-min-rate { + + uses common-queue; + + leaf rate { + type uint16; + description "OFPQT_MIN, len: 16"; + } + + } + + + + grouping queue-prop-max-rate { + + uses common-queue; + + leaf rate { + type uint16; + description "OFPQT_MAX, len: 16"; + } + + } + grouping queue-packet { + + + leaf queue-id { + type uint32; + description "id for the specific queue."; + } + + leaf port { + type uint32; + description "Port this queue is attached to."; + } + uses common-queue; + } + + grouping queue-config-request + { + leaf port { + type uint32; + description "Port to be queried."; + } + + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-management/src/main/yang/queue-config.yang b/opendaylight/md-sal/model/model-flow-management/src/main/yang/queue-config.yang new file mode 100644 index 0000000000..b362e3f080 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-management/src/main/yang/queue-config.yang @@ -0,0 +1,34 @@ +module queue-management { + namespace "urn:opendaylight:queue:config"; + prefix queue-cfg; + + import yang-ext {prefix ext; revision-date "2013-07-09";} + import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + + import opendaylight-queue-types {prefix queue; revision-date "2013-09-25";} + + + revision "2013-10-24" { + description "Initial revision of queue service"; + } + + grouping queue-entry { + leaf node { + type inv:node-connector-ref; + + } + uses queue:queue-config-request; + } + + container queues { + list queue { + key "id node"; + + leaf id { + type uint32; + } + + uses queue-entry; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/queue-service.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/queue-service.yang new file mode 100644 index 0000000000..bf79cbf635 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/queue-service.yang @@ -0,0 +1,29 @@ +module sal-queue { + namespace "urn:opendaylight:queue:service"; + prefix queue; + + import yang-ext {prefix ext; revision-date "2013-07-09";} + import opendaylight-inventory {prefix inv; revision-date "2013-08-19";} + import opendaylight-queue-types {prefix queue-type; revision-date "2013-09-25";} + + revision "2013-11-07" { + description "Initial revision of queue service"; + } + + grouping node-queue { + uses "inv:node-context-ref"; + + uses queue-type:queue-packet; + } + + + rpc get-queue { + output { + uses queue-type:queue-packet; + } + } + + notification queue-get-config-reply { + uses node-queue; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang index 5b565365a5..d29ddc0ddd 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang @@ -54,6 +54,10 @@ module opendaylight-group-statistics { rpc get-group-statistics { input { uses inv:node; + leaf group-id{ + type group-types:group-id; + } + } output { uses group-types:group-statistics-reply; diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index c356ff6b0e..a5e5c74f4c 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -16,7 +16,6 @@ - org.opendaylight.yangtools yang-maven-plugin diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java new file mode 100644 index 0000000000..c3fe5f70f1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java @@ -0,0 +1,53 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-broker-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public final class BindingBrokerImplModule extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingBrokerImplModule +{ + + private BundleContext bundleContext; + + public BindingBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public BindingBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, BindingBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + // Add custom validation for module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + BindingAwareBrokerImpl broker = new BindingAwareBrokerImpl(getBundleContext()); + broker.setDataBroker(getDataBrokerDependency()); + broker.setNotifyBroker(getNotificationServiceDependency()); + broker.start(); + return broker; + } + + public BundleContext getBundleContext() { + return bundleContext; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java new file mode 100644 index 0000000000..53902510be --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java @@ -0,0 +1,39 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-broker-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class BindingBrokerImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingBrokerImplModuleFactory +{ + + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + BindingBrokerImplModule module = (BindingBrokerImplModule) super.createModule(instanceName, dependencyResolver, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + BindingBrokerImplModule module = (BindingBrokerImplModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplSingletonModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplSingletonModule.java deleted file mode 100644 index ab94db988c..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplSingletonModule.java +++ /dev/null @@ -1,57 +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.config.yang.md.sal.binding.impl; - -import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl; -import org.osgi.framework.BundleContext; - -import com.google.common.base.Preconditions; - -/** -* -*/ -public final class BindingBrokerImplSingletonModule extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingBrokerImplSingletonModule -{ - - private BundleContext bundleContext; - - public BindingBrokerImplSingletonModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public BindingBrokerImplSingletonModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, BindingBrokerImplSingletonModule oldModule, java.lang.AutoCloseable oldInstance) { - super(identifier, dependencyResolver, oldModule, oldInstance); - } - - @Override - public void validate() { - super.validate(); - Preconditions.checkNotNull(getBundleContext()); - } - - - @Override - public boolean canReuseInstance(AbstractBindingBrokerImplSingletonModule oldModule) { - return true; - } - - - public java.lang.AutoCloseable createInstance() { - BindingAwareBrokerImpl broker = new BindingAwareBrokerImpl(getBundleContext()); - broker.start(); - return broker; - } - - public BundleContext getBundleContext() { - return bundleContext; - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplSingletonModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplSingletonModuleFactory.java deleted file mode 100644 index b0a63108f2..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplSingletonModuleFactory.java +++ /dev/null @@ -1,56 +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.config.yang.md.sal.binding.impl; - -import org.opendaylight.controller.config.api.DependencyResolver; -import org.opendaylight.controller.config.api.DependencyResolverFactory; -import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.config.spi.Module; -import org.osgi.framework.BundleContext; - -import java.util.Collections; -import java.util.Set; - -/** -* -*/ -public class BindingBrokerImplSingletonModuleFactory extends - org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingBrokerImplSingletonModuleFactory { - - private static final String SINGLETON_NAME = "binding-broker-singleton"; - public static ModuleIdentifier SINGLETON_IDENTIFIER = new ModuleIdentifier(NAME, SINGLETON_NAME); - - @Override - public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { - throw new UnsupportedOperationException("Only default instance supported."); - } - - @Override - public Module createModule(String instanceName, DependencyResolver dependencyResolver, - DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { - Module instance = super.createModule(instanceName, dependencyResolver, old, bundleContext); - ((BindingBrokerImplSingletonModule)instance).setBundleContext(bundleContext); - return instance; - } - - @Override - public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, - BundleContext bundleContext) { - - DependencyResolver dependencyResolver = dependencyResolverFactory - .createDependencyResolver(SINGLETON_IDENTIFIER); - BindingBrokerImplSingletonModule instance = new BindingBrokerImplSingletonModule(SINGLETON_IDENTIFIER, - dependencyResolver); - instance.setBundleContext(bundleContext); - - return Collections.singleton(instance); - } - -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java new file mode 100644 index 0000000000..8cbfbb6da2 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java @@ -0,0 +1,83 @@ +/** + * Generated file + + * Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-data-broker + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 20 17:33:01 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; +import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.data.DataProviderService; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.osgi.framework.BundleContext; + +import com.google.common.util.concurrent.MoreExecutors; + +/** +* +*/ +public final class DataBrokerImplModule extends + org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModule { + + private BundleContext bundleContext; + + public DataBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public DataBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + DataBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + } + + @Override + public java.lang.AutoCloseable createInstance() { + DataBrokerImpl dataBindingBroker = new DataBrokerImpl(); + + // FIXME: obtain via dependency management + ExecutorService executor = Executors.newCachedThreadPool(); + ExecutorService listeningExecutor = MoreExecutors.listeningDecorator(executor); + dataBindingBroker.setExecutor(listeningExecutor); + + + + Broker domBroker = getDomBrokerDependency(); + BindingIndependentMappingService mappingService = getMappingServiceDependency(); + + if (domBroker != null && mappingService != null) { + BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector(); + runtimeMapping.setMappingService(mappingService); + runtimeMapping.setBaDataService(dataBindingBroker); + domBroker.registerProvider(runtimeMapping, getBundleContext()); + } + + return dataBindingBroker; + } + + public BundleContext getBundleContext() { + return bundleContext; + } + + public void setBundleContext(BundleContext bundleContext2) { + this.bundleContext = bundleContext2; + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java new file mode 100644 index 0000000000..4022dd44ef --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java @@ -0,0 +1,38 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-data-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class DataBrokerImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModuleFactory +{ + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + DataBrokerImplModule module = (DataBrokerImplModule) super.createModule(instanceName, dependencyResolver, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + DataBrokerImplModule module = (DataBrokerImplModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java new file mode 100644 index 0000000000..72231d17d1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java @@ -0,0 +1,48 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-notification-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl; + +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +/** +* +*/ +public final class NotificationBrokerImplModule extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractNotificationBrokerImplModule +{ + + public NotificationBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public NotificationBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, NotificationBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + // Add custom validation for module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + ExecutorService executor = Executors.newFixedThreadPool(5); + ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(executor); + NotificationBrokerImpl broker = new NotificationBrokerImpl(listeningExecutor); + return broker; + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModuleFactory.java new file mode 100644 index 0000000000..24ca0bbfaa --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModuleFactory.java @@ -0,0 +1,19 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-notification-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +/** +* +*/ +public class NotificationBrokerImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractNotificationBrokerImplModuleFactory +{ + + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RpcBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RpcBrokerImplModule.java new file mode 100644 index 0000000000..7824da8939 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RpcBrokerImplModule.java @@ -0,0 +1,37 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-rpc-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +/** +* +*/ +public final class RpcBrokerImplModule extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractRpcBrokerImplModule +{ + + public RpcBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public RpcBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, RpcBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + // Add custom validation for module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + //TODO:implement + throw new java.lang.UnsupportedOperationException("Unimplemented stub method"); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RpcBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RpcBrokerImplModuleFactory.java new file mode 100644 index 0000000000..61c7364a43 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RpcBrokerImplModuleFactory.java @@ -0,0 +1,19 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: binding-rpc-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:33:01 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +/** +* +*/ +public class RpcBrokerImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractRpcBrokerImplModuleFactory +{ + + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java new file mode 100644 index 0000000000..6537b4c64d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -0,0 +1,63 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: runtime-generated-mapping +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 18:20:19 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import javassist.ClassPool; + +import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; +import org.osgi.framework.BundleContext; + +import com.google.common.base.Preconditions; + +/** +* +*/ +public final class RuntimeMappingModule extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractRuntimeMappingModule +{ + + private BundleContext bundleContext; + + public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, RuntimeMappingModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + Preconditions.checkNotNull(bundleContext); + // Add custom validation for module attributes here. + } + + @Override + public boolean canReuseInstance(AbstractRuntimeMappingModule oldModule) { + return true; + } + + @Override + public java.lang.AutoCloseable createInstance() { + RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(); + ClassPool pool = new ClassPool(); // Should be default singleton + service.setPool(pool); + service.start(getBundleContext()); + return service; + } + + private BundleContext getBundleContext() { + return bundleContext; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModuleFactory.java new file mode 100644 index 0000000000..f104c73ba3 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModuleFactory.java @@ -0,0 +1,58 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-binding-broker-impl yang module local name: runtime-generated-mapping +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 18:20:19 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.binding.impl; + +import java.util.Collections; +import java.util.Set; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DependencyResolverFactory; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class RuntimeMappingModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractRuntimeMappingModuleFactory +{ + + + private static RuntimeMappingModule SINGLETON = null; + private static ModuleIdentifier IDENTIFIER = new ModuleIdentifier(NAME, "runtime-mapping-singleton"); + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + throw new UnsupportedOperationException("Only default instance supported"); + } + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + RuntimeMappingModule module = (RuntimeMappingModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, + BundleContext bundleContext) { + if(SINGLETON == null) { + DependencyResolver dependencyResolver = dependencyResolverFactory.createDependencyResolver(IDENTIFIER); + SINGLETON = new RuntimeMappingModule(IDENTIFIER , dependencyResolver); + SINGLETON.setBundleContext(bundleContext); + } + + + return Collections.singleton(SINGLETON); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend index 02da174656..116a8177f9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend @@ -30,7 +30,7 @@ class RpcRoutingTableImpl implement } - override getRoute(InstanceIdentifier nodeInstance) { + override getRoute(InstanceIdentifier nodeInstance) { val ret = routes.get(nodeInstance); if(ret !== null) { return ret; @@ -44,6 +44,6 @@ class RpcRoutingTableImpl implement @SuppressWarnings("rawtypes") override updateRoute(InstanceIdentifier path, S service) { - routes.put(path as InstanceIdentifier,service); + routes.put(path as InstanceIdentifier,service); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 93c192c0af..801e4984c0 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -11,7 +11,6 @@ import javassist.ClassPool import org.opendaylight.yangtools.yang.binding.RpcService import javassist.CtClass -import static com.google.common.base.Preconditions.* import javassist.CtMethod import org.opendaylight.yangtools.yang.binding.InstanceIdentifier import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext @@ -65,9 +64,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } override getRouterFor(Class iface) { - val contexts = new HashSet> - - val instance = >withClassLoader(iface.classLoader) [ | + val instance = >withClassLoaderAndLock(iface.classLoader,lock) [ | val supertype = iface.asCtClass val metadata = supertype.rpcMetadata; val targetCls = createClass(iface.routerName, supertype) [ @@ -210,7 +207,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co ] val finalClass = targetCls.toClass(iface.classLoader, iface.protectionDomain) return new RuntimeGeneratedInvokerPrototype(supportedNotification, - finalClass as Class); + finalClass as Class>); } @@ -218,13 +215,16 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co protected def resolveInvokerClass(Class class1) { - val invoker = invokerClasses.get(class1); - if (invoker !== null) { - return invoker; - } - val newInvoker = generateListenerInvoker(class1); - invokerClasses.put(class1, newInvoker); - return newInvoker + return withClassLoaderAndLock(class1.classLoader,lock) [| + val invoker = invokerClasses.get(class1); + if (invoker !== null) { + return invoker; + } + val newInvoker = generateListenerInvoker(class1); + invokerClasses.put(class1, newInvoker); + return newInvoker + + ] } } @@ -235,7 +235,7 @@ package class RuntimeGeneratedInvoker implements NotificationInvoker { val NotificationListener delegate; @Property - var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; + var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; @Property var RuntimeGeneratedInvokerPrototype prototype; @@ -243,7 +243,7 @@ package class RuntimeGeneratedInvoker implements NotificationInvoker { new(NotificationListener delegate, RuntimeGeneratedInvokerPrototype prototype) { _delegate = delegate; _prototype = prototype; - _invocationProxy = prototype.protoClass.newInstance; + _invocationProxy = prototype.protoClass.newInstance as org.opendaylight.controller.sal.binding.api.NotificationListener; RuntimeCodeHelper.setDelegate(_invocationProxy, delegate); } @@ -262,7 +262,7 @@ package class RuntimeGeneratedInvokerPrototype { val Set> supportedNotifications; @Property - val Class protoClass; + val Class> protoClass; } package class RpcServiceMetadata { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java index c2b5635af3..c3f102ac45 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/BindingClassListener.java @@ -4,4 +4,5 @@ public interface BindingClassListener { void onBindingClassCaptured(Class cls); + void onBindingClassProcessed(Class cls); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java index 19e9961760..35f48745f9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java @@ -30,8 +30,8 @@ public class CodecMapping { } } - public static void setClassToCaseMap(Class codec, - Map classToCaseRawCodec) { + public static void setClassToCaseMap(Class> codec, + Map,BindingCodec> classToCaseRawCodec) { Field instanceIdField; try { instanceIdField = codec.getField(CLASS_TO_CASE_MAP); @@ -47,8 +47,8 @@ public class CodecMapping { } - public static void setCompositeNodeToCaseMap(Class codec, - Map compositeToCase) { + public static void setCompositeNodeToCaseMap(Class> codec, + Map> compositeToCase) { Field instanceIdField; try { instanceIdField = codec.getField(COMPOSITE_TO_CASE); @@ -63,7 +63,7 @@ public class CodecMapping { } public static void setAugmentationCodec(Class, Object>> dataCodec, - BindingCodec augmentableCodec) { + BindingCodec augmentableCodec) { Field instanceIdField; try { instanceIdField = dataCodec.getField(AUGMENTATION_CODEC); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java index 3f74c9eaf4..0a8ea84cf6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java @@ -9,6 +9,8 @@ public interface GeneratorListener { + void onClassProcessed(Class cl); + void onCodecCreated(Class codec); void onValueCodecCreated(Class valueClass,Class valueCodec); void onChoiceCodecCreated(Class choiceClass,Class,Object>> choiceCodec); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend index fd02fde407..2706609806 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend @@ -95,6 +95,7 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { return new NodeIdentifier(QName.create(previousQname,qname.localName)); } + @SuppressWarnings("rawtypes") private def dispatch PathArgument serializePathArgument(IdentifiableItem argument, QName previousQname) { val Map predicates = new HashMap(); val type = argument.type; @@ -111,7 +112,7 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { return new NodeIdentifierWithPredicates(QName.create(previousQname,qname.localName),predicates); } - def resolveQname(Class class1) { + def resolveQname(Class class1) { val qname = classToQName.get(class1); if(qname !== null) { return qname; @@ -119,5 +120,6 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { val qnameField = class1.getField("QNAME"); val qnameValue = qnameField.get(null) as QName; classToQName.put(class1,qnameValue); + return qnameValue; } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index e8e4c4375d..b81100836f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -36,6 +36,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.BindingCodec; import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -120,6 +121,9 @@ public class LazyGeneratedCodecRegistry implements // ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName()); @SuppressWarnings("rawtypes") WeakReference weakRef = typeToClass.get(typeref); + if(weakRef == null) { + LOG.error("Could not find loaded class for path: {} and type: {}",path,typeref.getFullyQualifiedName()); + } return weakRef.get(); } @@ -147,9 +151,29 @@ public class LazyGeneratedCodecRegistry implements // @Override @SuppressWarnings("rawtypes") public void bindingClassEncountered(Class cls) { + ConcreteType typeRef = Types.typeForClass(cls); + if(typeToClass.containsKey(typeRef)) { + return; + } + LOG.info("Binding Class {} encountered.",cls); WeakReference weakRef = new WeakReference<>(cls); typeToClass.put(typeRef, weakRef); + if(DataObject.class.isAssignableFrom(cls)) { + @SuppressWarnings({"unchecked","unused"}) + Object cdc = getCodecForDataObject((Class) cls); + } + } + + @Override + public void onClassProcessed(Class cls) { + ConcreteType typeRef = Types.typeForClass(cls); + if(typeToClass.containsKey(typeRef)) { + return; + } + LOG.info("Binding Class {} encountered.",cls); + WeakReference weakRef = new WeakReference<>((Class) cls); + typeToClass.put(typeRef, weakRef); } private DataSchemaNode getSchemaNode(List path) { @@ -280,6 +304,12 @@ public class LazyGeneratedCodecRegistry implements // ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode .getValue().getName()); ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey()); + if (node == null) { + LOG.error("YANGTools Bug: SchemaNode for {}, with path {} was not found in context.", + typeref.getFullyQualifiedName(), caseNode.getKey()); + continue; + } + @SuppressWarnings("rawtypes") ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node); typeToCaseNodes.putIfAbsent(typeref, value); @@ -300,7 +330,7 @@ public class LazyGeneratedCodecRegistry implements // BindingCodec, Object> delegate = newInstanceOf(choiceCodec); ChoiceCodecImpl newCodec = new ChoiceCodecImpl(delegate); choiceCodecs.put(choiceClass, newCodec); - CodecMapping.setClassToCaseMap(choiceCodec, (Map) classToCaseRawCodec); + CodecMapping.setClassToCaseMap(choiceCodec, (Map, BindingCodec>) classToCaseRawCodec); CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase()); } @@ -540,7 +570,7 @@ public class LazyGeneratedCodecRegistry implements // public BindingCodec get(Object key) { if (key instanceof Class) { Class cls = (Class) key; - bindingClassEncountered(cls); + //bindingClassEncountered(cls); ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls); return caseCodec.getDelegate(); } @@ -557,11 +587,6 @@ public class LazyGeneratedCodecRegistry implements // this.choiceCases = choiceCases; } - @Override - public Set> entrySet() { - return null; - } - @Override public BindingCodec get(Object key) { if (false == (key instanceof CompositeNode)) { @@ -575,6 +600,8 @@ public class LazyGeneratedCodecRegistry implements // } return null; } + + } /** @@ -585,7 +612,7 @@ public class LazyGeneratedCodecRegistry implements // * Key type */ @SuppressWarnings("rawtypes") - private static abstract class MapFacadeBase implements Map { + private static abstract class MapFacadeBase implements Map> { @Override public boolean containsKey(Object key) { @@ -613,7 +640,7 @@ public class LazyGeneratedCodecRegistry implements // } @Override - public Collection values() { + public Collection> values() { return null; } @@ -622,12 +649,12 @@ public class LazyGeneratedCodecRegistry implements // } @Override - public BindingCodec, Object> put(T key, BindingCodec value) { + public BindingCodec, Object> put(T key, BindingCodec value) { throw notModifiable(); } @Override - public void putAll(Map m) { + public void putAll(Map> m) { throw notModifiable(); } @@ -647,7 +674,8 @@ public class LazyGeneratedCodecRegistry implements // } @Override - public Set> entrySet() { + public Set>> entrySet() { + // TODO Auto-generated method stub return null; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend index 4614c60ca1..0ddc2c88c8 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -17,18 +17,9 @@ import java.util.Map.Entry import java.util.AbstractMap.SimpleEntry import org.opendaylight.yangtools.yang.model.api.SchemaPath import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil -import java.util.ArrayList -import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.binding.DataContainer -import static com.google.common.base.Preconditions.*; -import java.util.List -import org.opendaylight.yangtools.yang.data.api.Node -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl -import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl -import org.opendaylight.yangtools.concepts.Delegator import java.util.concurrent.ConcurrentMap import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType -import org.opendaylight.yangtools.yang.binding.BindingCodec import com.google.common.collect.HashMultimap import com.google.common.util.concurrent.SettableFuture import java.util.concurrent.Future @@ -39,8 +30,11 @@ import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec import org.opendaylight.yangtools.binding.generator.util.Types +import org.osgi.framework.BundleContext +import java.util.Hashtable +import org.osgi.framework.ServiceRegistration -class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener { +class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { @Property ClassPool pool; @@ -65,6 +59,8 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer val promisedTypeDefinitions = HashMultimap.>create; val promisedSchemas = HashMultimap.>create; + + ServiceRegistration listenerRegistration override onGlobalContextUpdated(SchemaContext arg0) { recreateBindingContext(arg0); @@ -139,6 +135,10 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer val ret = transformer.deserialize(node)?.value as DataObject; return ret; } + + override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) { + return registry.instanceIdentifierCodec.deserialize(entry); + } private def void updateBindingFor(Map map, SchemaContext module) { for (entry : map.entrySet) { @@ -152,7 +152,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } } - public def void start() { + public def void start(BundleContext ctx) { binding = new TransformerGenerator(pool); registry = new LazyGeneratedCodecRegistry() registry.generator = binding @@ -162,7 +162,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer binding.typeToDefinition = typeToDefinition binding.typeToSchemaNode = typeToSchemaNode binding.typeDefinitions = typeDefinitions - + if(ctx !== null) { + listenerRegistration = ctx.registerService(SchemaServiceListener,this,new Hashtable()); + } } private def getTypeDefinition(Type type) { @@ -215,4 +217,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } promisedSchemas.removeAll(builder); } + + override close() throws Exception { + listenerRegistration?.unregister(); + } + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend index 8e059aa22e..01390d7c41 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend @@ -95,6 +95,7 @@ class TransformerGenerator { return withClassLoaderAndLock(inputType.classLoader, lock) [ | val ret = getGeneratedClass(inputType) if (ret !== null) { + listener.onClassProcessed(inputType); return ret as Class, Object>>; } val ref = Types.typeForClass(inputType) @@ -102,6 +103,7 @@ class TransformerGenerator { val typeSpecBuilder = typeToDefinition.get(ref) val typeSpec = typeSpecBuilder.toInstance(); val newret = generateTransformerFor(inputType, typeSpec, node); + listener.onClassProcessed(inputType); return newret as Class, Object>>; ] } @@ -117,6 +119,7 @@ class TransformerGenerator { val typeSpecBuilder = typeToDefinition.get(ref) val typeSpec = typeSpecBuilder.toInstance(); val newret = generateAugmentationTransformerFor(inputType, typeSpec, node); + listener.onClassProcessed(inputType); return newret as Class, Object>>; ] } @@ -184,7 +187,7 @@ class TransformerGenerator { ] } - private def Class getGeneratedClass(Class cls) { + private def Class getGeneratedClass(Class cls) { try { return loadClassWithTCCL(cls.codecClassName) @@ -211,13 +214,15 @@ class TransformerGenerator { if (transformer !== null) { return transformer; } - val valueTransformer = generateValueTransformer(cls, type); - return valueTransformer; + return withClassLoaderAndLock(cls.classLoader,lock) [| + val valueTransformer = generateValueTransformer(cls, type); + return valueTransformer; + ] } private def generateKeyTransformerFor(Class inputType, GeneratedType typeSpec, ListSchemaNode node) { try { - log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) val properties = typeSpec.allProperties; val ctCls = createClass(inputType.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); @@ -235,7 +240,7 @@ class TransformerGenerator { _resultName = QNAME; } java.util.List _childNodes = new java.util.ArrayList(); - «inputType.name» value = («inputType.name») $2; + «inputType.resolvedName» value = («inputType.name») $2; «FOR key : node.keyDefinition» «val propertyName = key.getterName» «val keyDef = node.getDataChildByName(key)» @@ -261,7 +266,7 @@ class TransformerGenerator { «val property = properties.get(propertyName)» «deserializeProperty(keyDef, property, propertyName)»; «ENDFOR» - «inputType.name» _value = new «inputType.name»(«node.keyDefinition.keyConstructorList»); + «inputType.resolvedName» _value = new «inputType.name»(«node.keyDefinition.keyConstructorList»); return _value; } ''' @@ -291,10 +296,10 @@ class TransformerGenerator { } } - private def Class> generateCaseCodec(Class inputType, GeneratedType type, + private def Class> generateCaseCodec(Class inputType, GeneratedType type, ChoiceCaseNode node) { try { - log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + //log.info("Generating DOM Codec for {} with {}, TCCL is: {}", inputType, inputType.classLoader,Thread.currentThread.contextClassLoader) val ctCls = createClass(type.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); implementsType(BINDING_CODEC) @@ -308,7 +313,7 @@ class TransformerGenerator { «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; - «transformDataContainerBody(type.allProperties, node)» + «transformDataContainerBody(type,type.allProperties, node)» return ($r) _childNodes; } ''' @@ -349,9 +354,9 @@ class TransformerGenerator { } private def dispatch Class, Object>> generateTransformerFor( - Class inputType, GeneratedType typeSpec, SchemaNode node) { + Class inputType, GeneratedType typeSpec, SchemaNode node) { try { - log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); staticQNameField(inputType); @@ -396,9 +401,9 @@ class TransformerGenerator { } private def Class, Object>> generateAugmentationTransformerFor( - Class inputType, GeneratedType type, AugmentationSchema node) { + Class inputType, GeneratedType type, AugmentationSchema node) { try { - log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) val properties = type.allProperties val ctCls = createClass(type.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); @@ -446,7 +451,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; - ////System.out.println(_localQName + " " + _compositeNode); + //System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «FOR child : node.childNodes» «val signature = properties.getFor(child)» @@ -475,9 +480,9 @@ class TransformerGenerator { } private def dispatch Class, Object>> generateTransformerFor( - Class inputType, GeneratedType typeSpec, ChoiceNode node) { + Class inputType, GeneratedType typeSpec, ChoiceNode node) { try { - log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); //staticQNameField(inputType); @@ -500,7 +505,9 @@ class TransformerGenerator { return null; } java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue); - return (java.util.List) _codec.serialize(_input); + Object _ret = _codec.serialize(_input); + //System.out.println("«typeSpec.name»#toDomStatic: " + _ret); + return («List.name») _ret; } ''' ] @@ -617,7 +624,7 @@ class TransformerGenerator { return null; } java.util.Map _compositeNode = (java.util.Map) $2; - ////System.out.println(_localQName + " " + _compositeNode); + //System.out.println(_localQName + " " + _compositeNode); «type.builderName» _builder = new «type.builderName»(); «deserializeDataNodeContainerBody(type, node)» «deserializeAugmentations» @@ -660,7 +667,7 @@ class TransformerGenerator { String propertyName) ''' java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName. localName»")); - ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»); + //System.out.println("«propertyName»#deCode"+_dom_«propertyName»); java.util.List «propertyName» = new java.util.ArrayList(); if(_dom_«propertyName» != null) { java.util.List _serialized = new java.util.ArrayList(); @@ -668,15 +675,15 @@ class TransformerGenerator { boolean _hasNext = _iterator.hasNext(); while(_hasNext) { Object _listItem = _iterator.next(); - ////System.out.println(" item" + _listItem); + //System.out.println(" item" + _listItem); Object _value = «type.actualTypeArguments.get(0).serializer.resolvedName».fromDomStatic(_localQName,_listItem); - ////System.out.println(" value" + _value); + //System.out.println(" value" + _value); «propertyName».add(_value); _hasNext = _iterator.hasNext(); } } - ////System.out.println(" list" + «propertyName»); + //System.out.println(" list" + «propertyName»); ''' private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type, @@ -737,29 +744,38 @@ class TransformerGenerator { val returnType = typeSpec.valueReturnType; if (returnType == null) { - val ctCls = createDummyImplementation(inputType, typeSpec); val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) return ret as Class, Object>>; } + var hasBinding = false; + try { + val bindingCodecClass = loadClassWithTCCL(BINDING_CODEC.name); + hasBinding = bindingCodecClass !== null; + } catch (ClassNotFoundException e) { + hasBinding = false; + } + val hasYangBinding = hasBinding val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - implementsType(BINDING_CODEC) - staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) - implementsType(BindingDeserializer.asCtClass) + if(hasYangBinding) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' { - ////System.out.println("«inputType.simpleName»#toDomValue: "+$1); + //System.out.println("«inputType.simpleName»#toDomValue: "+$1); if($1 == null) { return null; } «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1; - ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); + //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue); «returnType.resolvedName» _value = _encapsulatedValue.getValue(); - ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); + //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value); Object _domValue = «serializeValue(returnType, "_value")»; return _domValue; } @@ -776,7 +792,7 @@ class TransformerGenerator { modifiers = PUBLIC + FINAL + STATIC body = ''' { - ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); if($1 == null) { return null; @@ -849,13 +865,14 @@ class TransformerGenerator { return null; } - private def dispatch Class, Object>> generateValueTransformer( + private def dispatch Class generateValueTransformer( Class inputType, Enumeration typeSpec) { try { - log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) + //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader) val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); - implementsType(BINDING_CODEC) + //implementsType(BINDING_CODEC) + method(Object, "toDomValue", Object) [ modifiers = PUBLIC + FINAL + STATIC body = ''' @@ -891,7 +908,7 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) log.info("DOM Codec for {} was generated {}", inputType, ret) - return ret as Class, Object>>; + return ret; } catch (CodeGenerationException e) { throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e); } catch (Exception e) { @@ -982,7 +999,7 @@ class TransformerGenerator { «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; - «transformDataContainerBody(type.allProperties, node)» + «transformDataContainerBody(type,type.allProperties, node)» «serializeAugmentations» return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } @@ -993,7 +1010,7 @@ class TransformerGenerator { «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; - «transformDataContainerBody(type.allProperties, node)» + «transformDataContainerBody(type,type.allProperties, node)» «serializeAugmentations» return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } @@ -1004,7 +1021,7 @@ class TransformerGenerator { «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName()); java.util.List _childNodes = new java.util.ArrayList(); «type.resolvedName» value = («type.resolvedName») $2; - «transformDataContainerBody(type.allProperties, node)» + «transformDataContainerBody(type,type.allProperties, node)» «serializeAugmentations» return ($r) java.util.Collections.singletonMap(_resultName,_childNodes); } @@ -1019,11 +1036,11 @@ class TransformerGenerator { } ''' - private def transformDataContainerBody(Map properties, DataNodeContainer node) { + private def transformDataContainerBody(Type type,Map properties, DataNodeContainer node) { val ret = ''' «FOR child : node.childNodes.filter[!augmenting]» «var signature = properties.getFor(child)» - //System.out.println("«signature.key»" + value.«signature.key»()); + //System.out.println("«type.name»#«signature.key»" + value.«signature.key»()); «serializeProperty(child, signature.value, signature.key)» «ENDFOR» ''' @@ -1152,11 +1169,11 @@ class TransformerGenerator { return '''«typeSpec.resolvedName»$Broker$Codec$DOM''' } - private def codecClassName(Class typeSpec) { + private def codecClassName(Class typeSpec) { return '''«typeSpec.name»$Broker$Codec$DOM''' } - private def dispatch HashMap getAllProperties(GeneratedType type) { + private def HashMap getAllProperties(GeneratedType type) { val ret = new HashMap(); type.collectAllProperties(ret); return ret; @@ -1186,12 +1203,11 @@ class TransformerGenerator { return type.asCtClass.name; } - def String getResolvedName(Class type) { + def String getResolvedName(Class type) { return type.asCtClass.name; } def CtClass asCtClass(Type type) { - val name = type.fullyQualifiedName val cls = loadClassWithTCCL(type.fullyQualifiedName) return cls.asCtClass; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend index 31d5d0126f..1762aac090 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend @@ -44,17 +44,18 @@ import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils import java.util.concurrent.Executors import java.util.Collections import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.controller.sal.binding.impl.connect.dom.ConnectorActivator +import java.util.concurrent.locks.ReentrantLock +import java.util.concurrent.Callable +import java.util.WeakHashMap +import javax.annotation.concurrent.GuardedBy class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl) - private InstanceIdentifier root = InstanceIdentifier.builder().toInstance(); - private val clsPool = ClassPool.getDefault() - private var RuntimeCodeGenerator generator; - + private static val clsPool = ClassPool.getDefault() + public static var RuntimeCodeGenerator generator; /** * Map of all Managed Direct Proxies @@ -68,28 +69,29 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { * * */ - private val Map, RpcRouter> rpcRouters = new ConcurrentHashMap(); + private val Map, RpcRouter> rpcRouters = new WeakHashMap(); @Property - private var NotificationBrokerImpl notifyBroker - + private var NotificationProviderService notifyBroker + @Property - private var DataBrokerImpl dataBroker - + private var DataProviderService dataBroker + @Property var BundleContext brokerBundleContext - + ServiceRegistration notifyProviderRegistration - + ServiceRegistration notifyConsumerRegistration - + ServiceRegistration dataProviderRegistration - + ServiceRegistration dataConsumerRegistration - - ConnectorActivator connectorActivator - - + + private val proxyGenerationLock = new ReentrantLock; + + private val routerGenerationLock = new ReentrantLock; + public new(BundleContext bundleContext) { _brokerBundleContext = bundleContext; } @@ -99,27 +101,13 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { initGenerator(); val executor = Executors.newCachedThreadPool; + // Initialization of notificationBroker log.info("Starting MD-SAL: Binding Aware Notification Broker"); - notifyBroker = new NotificationBrokerImpl(executor); - notifyBroker.invokerFactory = generator.invokerFactory; log.info("Starting MD-SAL: Binding Aware Data Broker"); - dataBroker = new DataBrokerImpl(); - dataBroker.executor = executor; - val brokerProperties = newProperties(); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - notifyProviderRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker, - brokerProperties) - notifyConsumerRegistration = brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties) - dataProviderRegistration = brokerBundleContext.registerService(DataProviderService, dataBroker, brokerProperties) - dataConsumerRegistration = brokerBundleContext.registerService(DataBrokerService, dataBroker, brokerProperties) - - connectorActivator = new ConnectorActivator(dataBroker,brokerBundleContext); - connectorActivator.start(); log.info("MD-SAL: Binding Aware Broker Started"); } @@ -163,20 +151,37 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { * If proxy class does not exist for supplied service class it will be generated automatically. */ private def getManagedDirectProxy(Class service) { - var RpcProxyContext existing = null + if ((existing = managedProxies.get(service)) != null) { return existing.proxy } - val proxyInstance = generator.getDirectProxyFor(service) - val rpcProxyCtx = new RpcProxyContext(proxyInstance.class) - val properties = new Hashtable() - rpcProxyCtx.proxy = proxyInstance as RpcService - - properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY - rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties) - managedProxies.put(service, rpcProxyCtx) - return rpcProxyCtx.proxy + return withLock(proxyGenerationLock) [ | + val maybeProxy = managedProxies.get(service); + if (maybeProxy !== null) { + return maybeProxy.proxy; + } + + + val proxyInstance = generator.getDirectProxyFor(service) + val rpcProxyCtx = new RpcProxyContext(proxyInstance.class) + val properties = new Hashtable() + rpcProxyCtx.proxy = proxyInstance as RpcService + properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY + rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties) + managedProxies.put(service, rpcProxyCtx) + return rpcProxyCtx.proxy + ] + } + + private static def T withLock(ReentrantLock lock, Callable method) { + try { + lock.lock(); + val ret = method.call; + return ret; + } finally { + lock.unlock(); + } } /** @@ -190,7 +195,7 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { val osgiReg = context.bundleContext.registerService(type, service, properties); proxy.delegate = service; - return new RpcServiceRegistrationImpl(type, service, osgiReg,this); + return new RpcServiceRegistrationImpl(type, service, osgiReg, this); } def RoutedRpcRegistration registerRoutedRpcImplementation(Class type, T service, @@ -208,14 +213,20 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { } // We created Router - val newRouter = generator.getRouterFor(type); - checkState(newRouter !== null); - rpcRouters.put(type, newRouter); - - // We create / update Direct Proxy for router - val proxy = getManagedDirectProxy(type); - proxy.delegate = newRouter.invocationProxy - return newRouter; + return withLock(routerGenerationLock) [ | + val maybeRouter = rpcRouters.get(type); + if (maybeRouter !== null) { + return maybeRouter as RpcRouter; + } + + val newRouter = generator.getRouterFor(type); + checkState(newRouter !== null); + rpcRouters.put(type, newRouter); + // We create / update Direct Proxy for router + val proxy = getManagedDirectProxy(type); + proxy.delegate = newRouter.invocationProxy + return newRouter; + ] } @@ -230,8 +241,8 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { // Updating internal structure of registration routingTable.updateRoute(path, registration.instance) + // Update routing table / send announce to message bus - val success = paths.put(context, path); } @@ -263,32 +274,32 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, AutoCloseable { routingTable.removeRoute(path) } } - + protected def void unregisterRpcService(RpcServiceRegistrationImpl registration) { val type = registration.serviceType; - + val proxy = managedProxies.get(type); - if(proxy.proxy.delegate === registration.instance) { + if (proxy.proxy.delegate === registration.instance) { proxy.proxy.delegate = null; } } - + def createDelegate(Class type) { getManagedDirectProxy(type); } - + def getRpcRouters() { return Collections.unmodifiableMap(rpcRouters); } - + override close() { dataConsumerRegistration.unregister() dataProviderRegistration.unregister() notifyConsumerRegistration.unregister() notifyProviderRegistration.unregister() } - + } class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { @@ -332,7 +343,7 @@ class RoutedRpcRegistrationImpl extends AbstractObjectRegi checkClosed() broker.unregisterPath(this, context, path); } - + override getServiceType() { return router.serviceType; } @@ -343,24 +354,25 @@ class RoutedRpcRegistrationImpl extends AbstractObjectRegi } } -class RpcServiceRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { + +class RpcServiceRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { val ServiceRegistration osgiRegistration; private var BindingAwareBrokerImpl broker; - + @Property val Class serviceType; - public new(Class type, T service, ServiceRegistration osgiReg,BindingAwareBrokerImpl broker) { + public new(Class type, T service, ServiceRegistration osgiReg, BindingAwareBrokerImpl broker) { super(service); this._serviceType = type; this.osgiRegistration = osgiReg; - this.broker= broker; + this.broker = broker; } override protected removeRegistration() { broker.unregisterRpcService(this); broker = null; } - + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java index 7a1ca11fb6..2f4510d5b4 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.binding.impl; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; @@ -17,77 +18,85 @@ import org.opendaylight.yangtools.yang.common.RpcResult; public class DataBrokerImpl extends AbstractDataBroker, DataObject, DataChangeListener> implements - DataProviderService { + DataProviderService, AutoCloseable { + + + private final AtomicLong nextTransaction = new AtomicLong(); + public DataBrokerImpl() { setDataReadRouter(new BindingAwareDataReaderRouter()); } @Override public DataTransactionImpl beginTransaction() { - return new DataTransactionImpl(this); + String transactionId = "BA-" + nextTransaction.getAndIncrement(); + return new DataTransactionImpl(transactionId,this); } @Override + @Deprecated public T getData(DataStoreIdentifier store, Class rootType) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public T getData(DataStoreIdentifier store, T filter) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public T getCandidateData(DataStoreIdentifier store, Class rootType) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public T getCandidateData(DataStoreIdentifier store, T filter) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public Future> commit(DataStoreIdentifier store) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public DataObject getData(InstanceIdentifier data) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public DataObject getConfigurationData(InstanceIdentifier data) { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public void registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { - // TODO Auto-generated method stub - + throw new UnsupportedOperationException("Deprecated"); } @Override + @Deprecated public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { - // TODO Auto-generated method stub - + throw new UnsupportedOperationException("Deprecated"); } - + @Override + public void close() throws Exception { + + } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java index f7967beaae..b0eb9eeb42 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java @@ -15,8 +15,8 @@ public class DataTransactionImpl extends AbstractDataTransaction, NotificationListener> listeners; @Property var ExecutorService executor; - @Property - var RuntimeCodeGenerator generator; - - @Property - var NotificationInvokerFactory invokerFactory; - new(ExecutorService executor) { listeners = HashMultimap.create() this.executor = executor; @@ -108,7 +102,7 @@ class NotificationBrokerImpl implements NotificationProviderService { override registerNotificationListener( org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - val invoker = invokerFactory.invokerFor(listener); + val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener); for (notifyType : invoker.supportedNotifications) { listeners.put(notifyType, invoker.invocationProxy) } @@ -125,6 +119,11 @@ class NotificationBrokerImpl implements NotificationProviderService { listeners.remove(notifyType, reg.invoker.invocationProxy) } } + + override close() { + //FIXME: implement properly. + } + } class GenericNotificationRegistration extends AbstractObjectRegistration> implements ListenerRegistration> { @@ -177,7 +176,9 @@ class NotifyTask implements Callable { override call() { try { + log.info("Delivering notification {} to {}",notification,listener); listener.onNotification(notification); + log.info("Notification delivered {} to {}",notification,listener); } catch (Exception e) { log.error("Unhandled exception thrown by listener: {}", listener, e); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java index ff897aa41d..ccd6079cc9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java @@ -1,44 +1,64 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; +import java.util.Collection; import java.util.Collections; +import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; -import org.opendaylight.controller.md.sal.common.api.data.DataModification; -import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; import org.opendaylight.controller.sal.common.util.Rpcs; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; +import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; - -import com.google.common.base.Preconditions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BindingIndependentDataServiceConnector implements // RuntimeDataProvider, // - DataCommitHandler, DataObject> { + Provider { + + private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class); private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier + .builder().toInstance(); + private BindingIndependentMappingService mappingService; - private DataBrokerService biDataService; + private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; private DataProviderService baDataService; + private ConcurrentMap domOpenedTransactions = new ConcurrentHashMap<>(); + private ConcurrentMap bindingOpenedTransactions = new ConcurrentHashMap<>(); + + private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler(); + private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler(); + + private Registration, DataObject>> baCommitHandlerRegistration; + + private Registration> biCommitHandlerRegistration; + @Override public DataObject readOperationalData(InstanceIdentifier path) { - // TODO Auto-generated method stub org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); CompositeNode result = biDataService.readOperationalData(biPath); return mappingService.dataObjectFromDataDom(path, result); @@ -51,15 +71,7 @@ public class BindingIndependentDataServiceConnector implements // return mappingService.dataObjectFromDataDom(path, result); } - @Override - public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction, DataObject> requestCommit( - DataModification, DataObject> modification) { - - DataModificationTransaction translated = translateTransaction(modification); - return new WrappedTransaction(translated, modification); - } - - private DataModificationTransaction translateTransaction( + private DataModificationTransaction createBindingToDomTransaction( DataModification, DataObject> source) { DataModificationTransaction target = biDataService.beginTransaction(); for (Entry, DataObject> entry : source.getUpdatedConfigurationData() @@ -74,27 +86,133 @@ public class BindingIndependentDataServiceConnector implements // .toDataDom(entry); target.putOperationalData(biEntry.getKey(), biEntry.getValue()); } - for(InstanceIdentifier entry : source.getRemovedConfigurationData()) { + for (InstanceIdentifier entry : source.getRemovedConfigurationData()) { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); target.removeConfigurationData(biEntry); } - for(InstanceIdentifier entry : source.getRemovedOperationalData()) { + for (InstanceIdentifier entry : source.getRemovedOperationalData()) { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); target.removeOperationalData(biEntry); } return target; } - private class WrappedTransaction implements + private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction( + DataModification source) { + org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService + .beginTransaction(); + for (Entry entry : source + .getUpdatedConfigurationData().entrySet()) { + InstanceIdentifier baKey = mappingService.fromDataDom(entry.getKey()); + DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue()); + target.putConfigurationData(baKey, baData); + } + for (Entry entry : source + .getUpdatedOperationalData().entrySet()) { + InstanceIdentifier baKey = mappingService.fromDataDom(entry.getKey()); + DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue()); + target.putOperationalData(baKey, baData); + } + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeConfigurationData(baEntry); + } + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeOperationalData(baEntry); + } + return target; + } + + public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() { + return biDataService; + } + + public void setBiDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) { + this.biDataService = biDataService; + } + + public DataProviderService getBaDataService() { + return baDataService; + } + + public void setBaDataService(DataProviderService baDataService) { + this.baDataService = baDataService; + } + + public void start() { + baDataService.registerDataReader(ROOT, this); + baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler); + biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler); + baDataService.registerCommitHandlerListener(domToBindingCommitHandler); + } + + public void setMappingService(BindingIndependentMappingService mappingService) { + this.mappingService = mappingService; + } + + @Override + public Collection getProviderFunctionality() { + return Collections.emptyList(); + } + + @Override + public void onSessionInitiated(ProviderSession session) { + setBiDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class)); + start(); + } + + private class DomToBindingTransaction implements + DataCommitTransaction { + + private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing; + private final DataModification modification; + + public DomToBindingTransaction( + org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing, + DataModification modification) { + super(); + this.backing = backing; + this.modification = modification; + bindingOpenedTransactions.put(backing.getIdentifier(), this); + } + + @Override + public DataModification getModification() { + return modification; + } + + @Override + public RpcResult rollback() throws IllegalStateException { + // backing.cancel(); + return Rpcs. getRpcResult(true, null, Collections. emptySet()); + } + + @Override + public RpcResult finish() throws IllegalStateException { + Future> result = backing.commit(); + try { + RpcResult baResult = result.get(); + return Rpcs. getRpcResult(baResult.isSuccessful(), null, baResult.getErrors()); + } catch (InterruptedException e) { + throw new IllegalStateException("", e); + } catch (ExecutionException e) { + throw new IllegalStateException("", e); + } + } + } + + private class BindingToDomTransaction implements DataCommitTransaction, DataObject> { private DataModificationTransaction backing; private DataModification, DataObject> modification; - public WrappedTransaction(DataModificationTransaction backing, + public BindingToDomTransaction(DataModificationTransaction backing, DataModification, DataObject> modification) { this.backing = backing; this.modification = modification; + domOpenedTransactions.put(backing.getIdentifier(), this); } @Override @@ -106,46 +224,84 @@ public class BindingIndependentDataServiceConnector implements // public RpcResult finish() throws IllegalStateException { Future> result = backing.commit(); try { - RpcResult biresult = result.get(); + RpcResult biResult = result.get(); + return Rpcs. getRpcResult(biResult.isSuccessful(), null, biResult.getErrors()); } catch (InterruptedException e) { throw new IllegalStateException("", e); } catch (ExecutionException e) { throw new IllegalStateException("", e); + } finally { + domOpenedTransactions.remove(backing.getIdentifier()); } - return Rpcs. getRpcResult(true, null, Collections. emptySet()); } @Override public RpcResult rollback() throws IllegalStateException { - // backing.cancel(); + domOpenedTransactions.remove(backing.getIdentifier()); return Rpcs. getRpcResult(true, null, Collections. emptySet()); } - } - public DataBrokerService getBiDataService() { - return biDataService; - } + private class BindingToDomCommitHandler implements + DataCommitHandler, DataObject> { - public void setBiDataService(DataBrokerService biDataService) { - this.biDataService = biDataService; - } + @Override + public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction, DataObject> requestCommit( + DataModification, DataObject> bindingTransaction) { - public DataProviderService getBaDataService() { - return baDataService; - } + /** + * Transaction was created as DOM transaction, in that case we do + * not need to forward it back. + */ + if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) { - public void setBaDataService(DataProviderService baDataService) { - this.baDataService = baDataService; + return CommitHandlersTransactions.allwaysSuccessfulTransaction(bindingTransaction); + } + DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction); + BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction); + LOG.info("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(), + domTransaction.getIdentifier()); + return wrapped; + } } - public void start() { - baDataService.registerDataReader(ROOT, this); - baDataService.registerCommitHandler(ROOT, this); - } + private class DomToBindingCommitHandler implements // + RegistrationListener, DataObject>>, // + DataCommitHandler { - public void setMappingService(BindingIndependentMappingService mappingService) { - this.mappingService = mappingService; - } + @Override + public void onRegister(DataCommitHandlerRegistration, DataObject> registration) { + + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration.getPath()); + // FIXME: do registration based on only active commit handlers. + + } + @Override + public void onUnregister(DataCommitHandlerRegistration, DataObject> registration) { + // NOOP for now + // FIXME: do registration based on only active commit handlers. + } + + public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction requestCommit( + DataModification domTransaction) { + Object identifier = domTransaction.getIdentifier(); + + /** + * We checks if the transcation was originated in this mapper. If it + * was originated in this mapper we are returing allways success + * commit hanlder to prevent creating loop in two-phase commit and + * duplicating data. + */ + if (domOpenedTransactions.containsKey(identifier)) { + return CommitHandlersTransactions.allwaysSuccessfulTransaction(domTransaction); + } + + org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction); + DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction); + LOG.info("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(), + baTransaction.getIdentifier()); + return forwardedTransaction; + } + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java index 8e61c9b3ee..9e175b8cb0 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java @@ -17,6 +17,7 @@ public interface BindingIndependentMappingService { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(InstanceIdentifier path); DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result); - - + + InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry); + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CommitHandlersTransactions.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CommitHandlersTransactions.java new file mode 100644 index 0000000000..ea4837421d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/CommitHandlersTransactions.java @@ -0,0 +1,40 @@ +package org.opendaylight.controller.sal.binding.impl.connect.dom; + +import java.util.Collections; + +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class CommitHandlersTransactions { + + private static class AllwaysSuccessfulTransaction implements DataCommitTransaction { + + private final DataModification modification; + + public AllwaysSuccessfulTransaction(DataModification modification) { + this.modification = modification; + } + @Override + public RpcResult rollback() throws IllegalStateException { + return Rpcs.getRpcResult(true, null, Collections.emptyList()); + } + @Override + public RpcResult finish() throws IllegalStateException { + return Rpcs.getRpcResult(true, null, Collections.emptyList()); + } + + @Override + public DataModification getModification() { + return modification; + } + } + + + public static final

,D> AllwaysSuccessfulTransaction allwaysSuccessfulTransaction(DataModification modification) { + return new AllwaysSuccessfulTransaction<>(modification); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java deleted file mode 100644 index f69e664ee8..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/ConnectorActivator.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.opendaylight.controller.sal.binding.impl.connect.dom; - -import java.util.Collection; -import java.util.Collections; - -import javassist.ClassPool; - -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; -import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; - -public class ConnectorActivator implements Provider, ServiceTrackerCustomizer { - - BindingIndependentDataServiceConnector dataConnector; - BindingIndependentMappingService mappingService; - - private final DataProviderService baDataService; - private BundleContext context; - - private ServiceTracker brokerTracker; - - public ConnectorActivator(DataProviderService dataService, BundleContext context) { - baDataService = dataService; - this.context = context; - brokerTracker = new ServiceTracker<>(context, Broker.class, this); - } - - @Override - public Collection getProviderFunctionality() { - return Collections.emptySet(); - } - - @Override - public void onSessionInitiated(ProviderSession session) { - - RuntimeGeneratedMappingServiceImpl mappingImpl = new RuntimeGeneratedMappingServiceImpl(); - mappingImpl.setPool(new ClassPool()); - SchemaService schemaService = (session.getService(SchemaService.class)); - ClassPool pool = new ClassPool(); - mappingImpl.setBinding(new TransformerGenerator(pool)); - mappingImpl.start(); - schemaService.registerSchemaServiceListener(mappingImpl); - mappingService = mappingImpl; - dataConnector = new BindingIndependentDataServiceConnector(); - dataConnector.setBaDataService(baDataService); - dataConnector.setBiDataService(session.getService(DataBrokerService.class)); - dataConnector.setMappingService(mappingService); - dataConnector.start(); - } - - @Override - public Broker addingService(ServiceReference reference) { - Broker br= context.getService(reference); - br.registerProvider(this, context); - return br; - } - - @Override - public void modifiedService(ServiceReference reference, Broker service) { - // NOOP - } - - @Override - public void removedService(ServiceReference reference, Broker service) { - // NOOP - } - - public void start() { - brokerTracker.open(); - } -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java new file mode 100644 index 0000000000..3fc377f176 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java @@ -0,0 +1,25 @@ +package org.opendaylight.controller.sal.binding.impl.connect.dom; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.yangtools.concepts.Path; + +import com.google.common.util.concurrent.JdkFutureAdapters; + +public final class DataModificationTracker

,D> { + + ConcurrentMap> trackedTransactions = new ConcurrentHashMap<>(); + + + public void startTrackingModification(DataModification modification) { + trackedTransactions.putIfAbsent(modification.getIdentifier(), modification); + + + } + + public boolean containsIdentifier(Object identifier) { + return trackedTransactions.containsKey(identifier); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRoutingContext.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRoutingContext.java new file mode 100644 index 0000000000..e3a7235652 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRoutingContext.java @@ -0,0 +1,10 @@ +package org.opendaylight.controller.sal.binding.spi; + +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; + +public interface RpcRoutingContext { + + Class getContextType(); + Class getServiceType(); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang b/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang index 72bae68d4c..38770c193c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang +++ b/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang @@ -3,8 +3,10 @@ module opendaylight-sal-binding-broker-impl { namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl"; prefix "binding-impl"; - import config { prefix config; revision-date 2013-04-05; } - import opendaylight-md-sal-binding {prefix sal;} + import config { prefix config; revision-date 2013-04-05; } + import opendaylight-md-sal-binding {prefix sal;} + import opendaylight-md-sal-dom {prefix dom;} + import opendaylight-md-sal-common {prefix common;} description "Service definition for Binding Aware MD-SAL."; @@ -14,39 +16,123 @@ module opendaylight-sal-binding-broker-impl { "Initial revision"; } - identity binding-broker-impl-singleton { + identity binding-dom-mapping-service { + base config:service-type; + config:java-class "org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService"; + } + + + identity binding-broker-impl { base config:module-type; config:provided-service sal:binding-broker-osgi-registry; - config:java-name-prefix BindingBrokerImplSingleton; + config:java-name-prefix BindingBrokerImpl; + } + + identity binding-data-broker { + base config:module-type; + config:provided-service sal:binding-data-broker; + config:provided-service sal:binding-data-consumer-broker; + config:java-name-prefix DataBrokerImpl; } - - grouping rpc-routing-table { - + identity binding-rpc-broker { + base config:module-type; + config:provided-service sal:binding-rpc-registry; + config:java-name-prefix RpcBrokerImpl; + } + + identity binding-notification-broker { + base config:module-type; + config:provided-service sal:binding-notification-service; + config:provided-service sal:binding-notification-subscription-service; + config:java-name-prefix NotificationBrokerImpl; } + identity runtime-generated-mapping { + base config:module-type; + config:provided-service binding-dom-mapping-service; + config:java-name-prefix RuntimeMapping; + } - grouping rpc-router { - leaf module { - type string; + augment "/config:modules/config:module/config:configuration" { + case binding-broker-impl { + when "/config:modules/config:module/config:type = 'binding-broker-impl'"; + + /* + container rpc-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity sal:binding-rpc-registry; + } + } + }*/ + + container data-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity sal:binding-data-broker; + } + } + } + + container notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity sal:binding-notification-service; + } + } + } } - container routing-tables { - list routing-table { - uses rpc-routing-table; + } + + augment "/config:modules/config:module/config:configuration" { + case binding-data-broker { + when "/config:modules/config:module/config:type = 'binding-data-broker'"; + container dom-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-broker-osgi-registry; + } + } } + container mapping-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity binding-dom-mapping-service; + } + } + } } } + + augment "/config:modules/config:module/config:state" { + case runtime-generated-mapping { + when "/config:modules/config:module/config:type = 'runtime-generated-mapping'"; + } + } augment "/config:modules/config:module/config:state" { - case binding-broker-impl-singleton { - when "/config:modules/config:module/config:type = 'binding-broker-impl-singleton'"; - - container rpc-routers { - list rpc-router { - uses rpc-router; - } - } + case binding-data-broker { + when "/config:modules/config:module/config:type = 'binding-data-broker'"; + uses common:data-state; + } + } + augment "/config:modules/config:module/config:state" { + case binding-rpc-broker { + when "/config:modules/config:module/config:type = 'binding-rpc-broker'"; + uses common:rpc-state; + } + } + augment "/config:modules/config:module/config:state" { + case binding-notification-broker { + when "/config:modules/config:module/config:type = 'binding-notification-broker'"; + uses common:notification-state; } } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index 7d8a8f1fff..5b35861e9d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -27,7 +27,7 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; public abstract class AbstractDataServiceTest { - protected DataBrokerService biDataService; + protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; protected DataProviderService baDataService; /** @@ -67,7 +67,7 @@ public abstract class AbstractDataServiceTest { mappingService = mappingServiceImpl; File pathname = new File("target/gen-classes-debug"); //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath()); - mappingServiceImpl.start(); + mappingServiceImpl.start(null); //mappingServiceImpl.getBinding().setClassFileCapturePath(pathname); connectorServiceImpl = new BindingIndependentDataServiceConnector(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java index 4e7628fd06..f60ddb991d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java @@ -1,22 +1,21 @@ package org.opendaylight.controller.sal.binding.test.bugfix; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; + + import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; @@ -24,9 +23,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; @@ -35,10 +32,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -46,7 +44,6 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -68,17 +65,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, NODE_ID); - private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() // - .node(Nodes.class) // - .toInstance(); - - private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = // - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // - .node(Nodes.QNAME) // - .toInstance(); - - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() // - .node(Nodes.class) // + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // .child(Node.class, NODE_KEY).toInstance(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // @@ -99,9 +86,8 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) // .toInstance(); private static final InstanceIdentifier FLOW_INSTANCE_ID_BA = // - InstanceIdentifier.builder() // - .node(Flows.class) // - .node(Flow.class, FLOW_KEY) // + InstanceIdentifier.builder(Flows.class) // + .child(Flow.class, FLOW_KEY) // .toInstance(); @@ -142,6 +128,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { ListenableFuture task3Future = listenablePool.submit(task3); + @SuppressWarnings("unchecked") ListenableFuture> compositeFuture = Futures.allAsList(task1Future,task2Future,task3Future); Thread.sleep(500); @@ -180,8 +167,6 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { flow.setKey(FLOW_KEY); flow.setMatch(match.build()); flow.setNode(NODE_REF); - - InstructionsBuilder instructions = new InstructionsBuilder(); InstructionBuilder instruction = new InstructionBuilder(); ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); @@ -191,6 +176,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { actionList.add(new ActionBuilder().setAction(popMplsAction.build()).build()); applyActions.setAction(actionList ); + instruction.setInstruction(applyActions.build()); @@ -205,13 +191,37 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { assertNotNull(ret); assertEquals(TransactionStatus.COMMITED, ret.getResult()); } + + private void createFlow2() throws Exception { + DataModificationTransaction modification = baDataService.beginTransaction(); + long id = 123; + FlowKey key = new FlowKey(id, new NodeRef(NODE_INSTANCE_ID_BA)); + InstanceIdentifier path1; + FlowBuilder flow = new FlowBuilder(); + flow.setKey(key); + MatchBuilder match = new MatchBuilder(); + Ipv4MatchBuilder ipv4Match = new Ipv4MatchBuilder(); + // ipv4Match.setIpv4Destination(new Ipv4Prefix(cliInput.get(4))); + match.setLayer4Match(new TcpMatchBuilder().build()); + flow.setMatch(match.build()); + DropAction dropAction = new DropActionBuilder().build(); + // ActionBuilder action = new ActionBuilder(); + + // List actions = Collections + // .singletonList(action.build()); + // flow.setAction(actions); + flow.setPriority(2); + System.out.println("Putting the configuration Data................"); + path1 = InstanceIdentifier.builder(Flows.class).child(Flow.class, key).toInstance(); + // DataObject cls = (DataObject) modification.readConfigurationData(path1); + modification.putConfigurationData(path1, flow.build()); + modification.commit(); + + } private class CreateFlowTask implements Callable { - final Object startSyncObject; - public CreateFlowTask(Object startSync) { - startSyncObject = startSync; } @Override @@ -220,6 +230,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { //startSyncObject.wait(); //Thread.sleep(500); createFlow(); + createFlow2(); } catch (Exception e) { throw new RuntimeException(e); } @@ -228,10 +239,10 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { } private void verifyDataAreStoredProperly() { - CompositeNode biFlow = biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI); + CompositeNode biFlows = biDataService.readConfigurationData(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.of(Flows.QNAME)); + assertNotNull(biFlows); + CompositeNode biFlow = biFlows.getFirstCompositeByName(Flow.QNAME); assertNotNull(biFlow); - CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME, Match.QNAME.getLocalName())); - assertNotNull(biMatch); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java index 773bab80f1..4df10bc135 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java @@ -1,8 +1,6 @@ package org.opendaylight.controller.sal.binding.test.bugfix; -import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -13,43 +11,22 @@ import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; - -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import static org.junit.Assert.*; public class DOMCodecBug02Test extends AbstractDataServiceTest { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); - private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id"); - private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node"); - - private static final String FLOW_ID = "foo"; private static final String NODE_ID = "node:1"; private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); @@ -57,8 +34,7 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, NODE_ID); - private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() // - .node(Nodes.class) // + private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // .toInstance(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = // @@ -66,8 +42,7 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { .node(Nodes.QNAME) // .toInstance(); - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() // - .node(Nodes.class) // + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // .child(Node.class, NODE_KEY).toInstance(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java index ae54591a23..2cd396dedc 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java @@ -1,13 +1,7 @@ package org.opendaylight.controller.sal.binding.test.bugfix; - -import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; + import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; @@ -15,36 +9,24 @@ import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; + import static org.junit.Assert.*; @@ -58,17 +40,11 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, NODE_ID); - private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder() // - .node(Nodes.class) // + private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // .toInstance(); - private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODES_INSTANCE_ID_BI = // - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // - .node(Nodes.QNAME) // - .toInstance(); - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder() // - .node(Nodes.class) // + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY).toInstance(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // @@ -76,7 +52,6 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh .node(Nodes.QNAME) // .nodeWithKey(Node.QNAME, NODE_KEY_BI) // .toInstance(); - private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA); private DataChangeEvent, DataObject> receivedChangeEvent; @@ -120,6 +95,49 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh verifyNodes(nodes,original); + + testAddingNodeConnector(); + + + + testNodeRemove(); + + + } + + private void testAddingNodeConnector() throws Exception { + + NodeConnectorId ncId = new NodeConnectorId("openflow:1:bar"); + NodeConnectorKey nodeKey = new NodeConnectorKey(ncId ); + InstanceIdentifier ncInstanceId = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).child(NodeConnector.class, nodeKey).toInstance(); + NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder(); + ncBuilder.setId(ncId); + ncBuilder.setKey(nodeKey); + NodeConnector connector = ncBuilder.build(); + DataModificationTransaction transaction = baDataService.beginTransaction(); + transaction.putOperationalData(ncInstanceId, connector); + RpcResult result = transaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); + assertNotNull(node); + assertNotNull(node.getNodeConnector()); + assertFalse(node.getNodeConnector().isEmpty()); + NodeConnector readedNc = node.getNodeConnector().get(0); + assertNotNull(readedNc); + + + + + } + + private void testNodeRemove() throws Exception { + DataModificationTransaction transaction = baDataService.beginTransaction(); + transaction.removeOperationalData(NODE_INSTANCE_ID_BA); + RpcResult result = transaction.commit().get(); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); + assertNull(node); } private void verifyNodes(Nodes nodes,Node original) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java new file mode 100644 index 0000000000..0c7f039642 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java @@ -0,0 +1,8 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +public class RpcRegistrationNullPointer { + + + + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java index 7706cda750..e326fd0931 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java @@ -63,7 +63,7 @@ public class BrokerIntegrationTest extends AbstractDataServiceTest { assertNotNull(result2.getResult()); assertEquals(TransactionStatus.COMMITED, result.getResult()); - Nodes allNodes = (Nodes) baDataService.readConfigurationData(InstanceIdentifier.builder().node(Nodes.class) + Nodes allNodes = (Nodes) baDataService.readConfigurationData(InstanceIdentifier.builder(Nodes.class) .toInstance()); assertNotNull(allNodes); assertNotNull(allNodes.getNode()); @@ -100,7 +100,7 @@ public class BrokerIntegrationTest extends AbstractDataServiceTest { private static NodeRef createNodeRef(String string) { NodeKey key = new NodeKey(new NodeId(string)); - InstanceIdentifier path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key) + InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) .toInstance(); return new NodeRef(path); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java new file mode 100644 index 0000000000..63368bd6c8 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java @@ -0,0 +1,190 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + + + + + + + + + + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; + + + + + + + + + + + +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.sal.binding.impl.connect.dom.CommitHandlersTransactions; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + +import com.google.common.collect.ImmutableMap; + +public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest { + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id"); + private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node"); + private static final long FLOW_ID = 1234; + private static final String NODE_ID = "node:1"; + + private DataModification, DataObject> modificationCapture; + + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + + private static final Map NODE_KEY_BI = Collections. singletonMap(NODE_ID_QNAME, + NODE_ID); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // + .child(Node.class, NODE_KEY).toInstance(); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .nodeWithKey(Node.QNAME, NODE_KEY_BI) // + .toInstance(); + private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA); + + private static final FlowKey FLOW_KEY = new FlowKey(FLOW_ID, NODE_REF); + + private static final Map FLOW_KEY_BI = // + ImmutableMap. of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_INSTANCE_ID_BI); + + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = // + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Flows.QNAME) // + .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) // + .toInstance(); + + private static final InstanceIdentifier FLOWS_PATH_BA = // + InstanceIdentifier.builder(Flows.class) // + .toInstance(); + + + private static final InstanceIdentifier FLOW_INSTANCE_ID_BA = // + InstanceIdentifier.builder(Flows.class) // + .child(Flow.class, FLOW_KEY) // + .toInstance(); + + @Test + public void simpleModifyOperation() throws Exception { + + registerCommitHandler(); + + CompositeNode domflow = createXmlFlow(); + DataModificationTransaction biTransaction = biDataService.beginTransaction(); + biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow); + RpcResult biResult = biTransaction.commit().get(); + + assertNotNull(modificationCapture); + Flow flow = (Flow) modificationCapture.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA); + assertNotNull(flow); + assertNotNull(flow.getMatch()); + assertEquals(TransactionStatus.COMMITED, biResult.getResult()); + + } + + + + private void registerCommitHandler() { + DataCommitHandler, DataObject> flowTestCommitHandler = new DataCommitHandler, DataObject>() { + + + @Override + public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction, DataObject> requestCommit( + DataModification, DataObject> modification) { + modificationCapture = modification; + return CommitHandlersTransactions.allwaysSuccessfulTransaction(modification); + } + + + }; + Registration, DataObject>> registration = baDataService.registerCommitHandler(FLOWS_PATH_BA, flowTestCommitHandler); + assertNotNull(registration); + } + + private CompositeNode createXmlFlow() { + + FlowBuilder flow = new FlowBuilder(); + MatchBuilder match = new MatchBuilder(); + VlanMatchBuilder vlanBuilder = new VlanMatchBuilder(); + VlanIdBuilder vlanIdBuilder = new VlanIdBuilder(); + VlanId vlanId = new VlanId(10); + vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build()); + match.setVlanMatch(vlanBuilder.build()); + + flow.setKey(FLOW_KEY); + flow.setMatch(match.build()); + flow.setNode(NODE_REF); + InstructionsBuilder instructions = new InstructionsBuilder(); + InstructionBuilder instruction = new InstructionBuilder(); + ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); + List actionList = new ArrayList<>(); + PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder(); + popMplsAction.setEthernetType(34); + actionList.add(new ActionBuilder().setAction(popMplsAction.build()).build()); + + applyActions.setAction(actionList ); + + + + instruction.setInstruction(applyActions.build()); + + + List instructionList = Collections.singletonList(instruction.build()); + instructions.setInstruction(instructionList ); + + flow.setInstructions(instructions.build()); + + CompositeNode domFlow = mappingService.toDataDom(flow.build()); + return domFlow; + } +} diff --git a/opendaylight/md-sal/sal-binding-config/src/main/yang/opendaylight-md-sal-binding.yang b/opendaylight/md-sal/sal-binding-config/src/main/yang/opendaylight-md-sal-binding.yang index bf3d7abd1e..38f0da3ccc 100644 --- a/opendaylight/md-sal/sal-binding-config/src/main/yang/opendaylight-md-sal-binding.yang +++ b/opendaylight/md-sal/sal-binding-config/src/main/yang/opendaylight-md-sal-binding.yang @@ -23,6 +23,11 @@ module opendaylight-md-sal-binding { config:java-class "org.opendaylight.controller.sal.binding.api.data.DataProviderService"; } + identity binding-data-consumer-broker { + base "config:service-type"; + config:java-class "org.opendaylight.controller.sal.binding.api.data.DataBrokerService"; + } + identity binding-rpc-registry { base "config:service-type"; config:java-class "org.opendaylight.controller.sal.binding.api.RpcProviderRegistry"; @@ -33,4 +38,9 @@ module opendaylight-md-sal-binding { config:java-class "org.opendaylight.controller.sal.binding.api.NotificationProviderService"; } + identity binding-notification-subscription-service { + base "config:service-type"; + config:java-class "org.opendaylight.controller.sal.binding.api.NotificationService"; + } + } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-it/pom.xml b/opendaylight/md-sal/sal-binding-it/pom.xml index e242b9ecee..27d426791f 100644 --- a/opendaylight/md-sal/sal-binding-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-it/pom.xml @@ -1,215 +1,252 @@ - 4.0.0 - - sal-parent - org.opendaylight.controller - 1.0-SNAPSHOT - - sal-binding-it - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + sal-parent + org.opendaylight.controller + 1.0-SNAPSHOT + + sal-binding-it + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + - - 3.0.0 - 1.5.0 - - ../sal-binding-broker/target/jacoco.exec - ../sal-binding-broker/target/jacoco-it.exec - + + 3.0.0 + 1.5.0 + + ../sal-binding-broker/target/jacoco.exec + ../sal-binding-broker/target/jacoco-it.exec + 0.2.3-SNAPSHOT + 0.2.3-SNAPSHOT + - - - - org.ops4j.pax.exam - maven-paxexam-plugin - 1.2.4 - - - generate-config - - generate-depends-file - - - - - - org.jacoco - jacoco-maven-plugin - - org.opendaylight.controller.* - - - - pre-test - - prepare-agent - - - - post-test - test - - report - - - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - - org.ops4j.pax.exam - - - maven-paxexam-plugin - - - [1.2.4,) - - - - generate-depends-file - - - - - - - - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - ../sal-binding-broker/target/jacoco-it.exec - org.opendaylight.controller.* - - - - pre-test - - prepare-agent - - - - post-test - - true - - - - - - - + + + + org.ops4j.pax.exam + maven-paxexam-plugin + 1.2.4 + + + generate-config + + generate-depends-file + + + + + + org.jacoco + jacoco-maven-plugin + + org.opendaylight.controller.* + + + + pre-test + + prepare-agent + + + + post-test + test + + report + + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.ops4j.pax.exam + + + maven-paxexam-plugin + + + [1.2.4,) + + + + generate-depends-file + + + + + + + + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + ../sal-binding-broker/target/jacoco-it.exec + org.opendaylight.controller.* + + + + pre-test + + prepare-agent + + + + post-test + + true + + + + + + + - - - org.opendaylight.yangtools.thirdparty - xtend-lib-osgi - 2.4.3 - test - - - org.opendaylight.controller - sal-binding-broker-impl - 1.0-SNAPSHOT - provided - - - org.ops4j.pax.exam - pax-exam-container-native - ${exam.version} - test - - - org.ops4j.pax.exam - pax-exam-junit4 - ${exam.version} - test - - - org.ops4j.pax.exam - pax-exam - ${exam.version} - - compile - - - org.ops4j.pax.exam - pax-exam-link-mvn - ${exam.version} - test - - - equinoxSDK381 - org.eclipse.osgi - 3.8.1.v20120830-144521 - test - - - org.slf4j - log4j-over-slf4j - 1.7.2 - - - ch.qos.logback - logback-core - 1.0.9 - - - ch.qos.logback - logback-classic - 1.0.9 - - - org.mockito - mockito-all - test - - - org.opendaylight.controller.model - model-flow-service - 1.0-SNAPSHOT - provided - - - org.opendaylight.controller - config-manager - 0.2.3-SNAPSHOT - - - org.opendaylight.controller.model - model-flow-management - 1.0-SNAPSHOT - provided - - + + + org.opendaylight.yangtools.thirdparty + xtend-lib-osgi + 2.4.3 + test + + + org.opendaylight.controller + sal-binding-broker-impl + 1.0-SNAPSHOT + provided + + + org.ops4j.pax.exam + pax-exam-container-native + ${exam.version} + test + + + org.ops4j.pax.exam + pax-exam-junit4 + ${exam.version} + test + + + org.opendaylight.controller + config-netconf-connector + ${netconf.version} + test + + + org.opendaylight.controller + yang-store-impl + ${config.version} + + + org.opendaylight.controller + logback-config + ${config.version} + + + org.opendaylight.controller + config-persister-impl + ${config.version} + + + org.opendaylight.controller + config-persister-file-adapter + ${config.version} + + + org.opendaylight.controller + netconf-impl + ${netconf.version} + + + org.opendaylight.controller + netconf-client + ${netconf.version} + + + org.ops4j.pax.exam + pax-exam + ${exam.version} + + compile + + + org.ops4j.pax.exam + pax-exam-link-mvn + ${exam.version} + test + + + equinoxSDK381 + org.eclipse.osgi + 3.8.1.v20120830-144521 + test + + + org.slf4j + log4j-over-slf4j + 1.7.2 + + + ch.qos.logback + logback-core + 1.0.9 + + + ch.qos.logback + logback-classic + 1.0.9 + + + org.mockito + mockito-all + test + + + org.opendaylight.controller.model + model-flow-service + 1.0-SNAPSHOT + provided + + + org.opendaylight.controller + config-manager + 0.2.3-SNAPSHOT + + + org.opendaylight.controller.model + model-flow-management + 1.0-SNAPSHOT + provided + + org.opendaylight.yangtools.thirdparty antlr4-runtime-osgi-nohead 4.0 - - + + diff --git a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java index 2f9c397632..0eace4daac 100644 --- a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java +++ b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java @@ -4,9 +4,12 @@ import static org.ops4j.pax.exam.CoreOptions.frameworkProperty; import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.repository; +import static org.ops4j.pax.exam.CoreOptions.repositories; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.options.DefaultCompositeOption; +import org.ops4j.pax.exam.util.PathUtils; public class TestHelper { @@ -15,62 +18,107 @@ public class TestHelper { public static final String CONTROLLER_MODELS = "org.opendaylight.controller.model"; public static final String YANGTOOLS_MODELS = "org.opendaylight.yangtools.model"; + private static final String OPENDAYLIGHT_SNAPSHOT = "http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/"; + private static final String OPENDAYLIGHT_RELEASE = "http://nexus.opendaylight.org/content/repositories/opendaylight.release/"; public static Option mdSalCoreBundles() { return new DefaultCompositeOption( // - mavenBundle(YANGTOOLS, "concepts").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-binding").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-common").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-common").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-common-api").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-common-impl").versionAsInProject(), // - - mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(), - mavenBundle("com.google.guava", "guava").versionAsInProject(), // + mavenBundle(YANGTOOLS, "concepts").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "yang-binding").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "yang-common").versionAsInProject(), // // + mavenBundle(CONTROLLER, "sal-common").versionAsInProject(), // // + mavenBundle(CONTROLLER, "sal-common-api").versionAsInProject(), // // + mavenBundle(CONTROLLER, "sal-common-impl").versionAsInProject(), // // + + mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(), // + mavenBundle("com.google.guava", "guava").versionAsInProject(), // // mavenBundle(YANGTOOLS + ".thirdparty", "xtend-lib-osgi").versionAsInProject() // ); } public static Option configMinumumBundles() { return new DefaultCompositeOption( - mavenBundle(CONTROLLER, "config-api").versionAsInProject(), // - mavenBundle(CONTROLLER, "config-manager").versionAsInProject(), // - mavenBundle("commons-io", "commons-io").versionAsInProject() - ); + mavenBundle("org.opendaylight.bgpcep", "framework").versionAsInProject(), // + mavenBundle("org.opendaylight.bgpcep", "util").versionAsInProject(), // + mavenBundle("commons-codec", "commons-codec").versionAsInProject(), + + mavenBundle(CONTROLLER, "config-api").versionAsInProject(), // // + mavenBundle(CONTROLLER, "config-manager").versionAsInProject(), // // + mavenBundle("commons-io", "commons-io").versionAsInProject(), // + mavenBundle(CONTROLLER, "config-api").versionAsInProject(), // + mavenBundle(CONTROLLER, "config-manager").versionAsInProject(), // + mavenBundle(CONTROLLER, "config-util").versionAsInProject(), // + mavenBundle(CONTROLLER, "yang-jmx-generator").versionAsInProject(), // + mavenBundle(CONTROLLER, "yang-store-api").versionAsInProject(), // + mavenBundle(CONTROLLER, "yang-store-impl").versionAsInProject(), // + mavenBundle(CONTROLLER, "logback-config").versionAsInProject(), // + mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), // + mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), // + + mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), // + mavenBundle(CONTROLLER, "netconf-util").versionAsInProject(), // + mavenBundle(CONTROLLER + ".thirdparty", "ganymed", "1.0-SNAPSHOT"), // + mavenBundle(CONTROLLER, "netconf-mapping-api").versionAsInProject(), // + + mavenBundle(CONTROLLER, "config-persister-impl").versionAsInProject(), // + + mavenBundle("io.netty", "netty-handler").versionAsInProject(), // + mavenBundle("io.netty", "netty-codec").versionAsInProject(), // + mavenBundle("io.netty", "netty-buffer").versionAsInProject(), // + mavenBundle("io.netty", "netty-transport").versionAsInProject(), // + mavenBundle("io.netty", "netty-common").versionAsInProject(), // + + mavenBundle("org.opendaylight.controller.thirdparty", "exificient", "0.9.2-SNAPSHOT"), // + + mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"), + mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"), + + mavenBundle(CONTROLLER, "config-netconf-connector").versionAsInProject(), // + mavenBundle(CONTROLLER, "netconf-impl").versionAsInProject(), // + + mavenBundle(CONTROLLER, "config-persister-file-adapter").versionAsInProject().noStart()); + } - + public static Option bindingAwareSalBundles() { return new DefaultCompositeOption( // - mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(), - mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), // - mavenBundle("org.javassist", "javassist").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), // - - mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(), - mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(), - - - mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), // - mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), // - mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(), + mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), // // + mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(), // + mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), // // + mavenBundle("org.javassist", "javassist").versionAsInProject(), // // + mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), // // + + mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(), // mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), + + mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(), // + mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(), // + mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(), // + mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(), mavenBundle(YANGTOOLS, + "binding-generator-spi").versionAsInProject(), // mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(), - - + mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), // - mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), // + mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), // - - mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject() // - ); + + mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // // + + systemProperty("netconf.tcp.address").value("0.0.0.0"), // + systemProperty("netconf.tcp.port").value("18383"), // + systemProperty("netconf.config.persister.storageAdapterClass").value( + "org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter"), // + systemProperty("fileStorage").value(PathUtils.getBaseDir() + "/src/test/resources/controller.config"), // + systemProperty("numberOfBackups").value("1") // + //systemProperty("yangstore.blacklist").value(".*controller.model.*") // + + ); } @@ -83,8 +131,8 @@ public class TestHelper { public static Option flowCapableModelBundles() { return new DefaultCompositeOption( // - mavenBundle(CONTROLLER_MODELS, "model-flow-base").versionAsInProject(), // - mavenBundle(CONTROLLER_MODELS, "model-flow-service").versionAsInProject(), // + mavenBundle(CONTROLLER_MODELS, "model-flow-base").versionAsInProject(), // // + mavenBundle(CONTROLLER_MODELS, "model-flow-service").versionAsInProject(), // // mavenBundle(CONTROLLER_MODELS, "model-inventory").versionAsInProject() // ); @@ -92,22 +140,18 @@ public class TestHelper { public static Option baseModelBundles() { return new DefaultCompositeOption( // - mavenBundle(YANGTOOLS_MODELS, "yang-ext").versionAsInProject(), // - mavenBundle(YANGTOOLS_MODELS, "ietf-inet-types").versionAsInProject(), // - mavenBundle(YANGTOOLS_MODELS, "ietf-yang-types").versionAsInProject(), // - mavenBundle(YANGTOOLS_MODELS, "opendaylight-l2-types").versionAsInProject(), // + mavenBundle(YANGTOOLS_MODELS, "yang-ext").versionAsInProject(), // // + mavenBundle(YANGTOOLS_MODELS, "ietf-inet-types").versionAsInProject(), // // + mavenBundle(YANGTOOLS_MODELS, "ietf-yang-types").versionAsInProject(), // // + mavenBundle(YANGTOOLS_MODELS, "opendaylight-l2-types").versionAsInProject(), // // mavenBundle(CONTROLLER_MODELS, "model-inventory").versionAsInProject()); } public static Option junitAndMockitoBundles() { return new DefaultCompositeOption( - // Repository required to load harmcrest (OSGi-fied version). - repository("http://repository.springsource.com/maven/bundles/external").id( - "com.springsource.repository.bundles.external"), - - // Mockito - mavenBundle("org.mockito", "mockito-all", "1.9.5"), - junitBundles(), + // Repository required to load harmcrest (OSGi-fied version). + // Mockito + mavenBundle("org.mockito", "mockito-all", "1.9.5"), junitBundles(), /* * Felix has implicit boot delegation enabled by default. It diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java index 41b1e310a0..338561ab48 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java @@ -11,6 +11,7 @@ import org.ops4j.pax.exam.Configuration; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.junit.PaxExam; import org.ops4j.pax.exam.options.DefaultCompositeOption; +import org.ops4j.pax.exam.util.Filter; import org.ops4j.pax.exam.util.PathUtils; import org.osgi.framework.BundleContext; @@ -24,8 +25,9 @@ public abstract class AbstractTest { public static final String YANGTOOLS_MODELS = "org.opendaylight.yangtools.model"; @Inject + @Filter(timeout=60*1000) BindingAwareBroker broker; - + @Inject BundleContext bundleContext; @@ -55,13 +57,14 @@ public abstract class AbstractTest { mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), // mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), // mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), // + systemProperty("osgi.bundles.defaultStartLevel").value("4"), - configMinumumBundles(), + mdSalCoreBundles(), bindingAwareSalBundles(), - + configMinumumBundles(), // BASE Models baseModelBundles(), flowCapableModelBundles(), junitAndMockitoBundles()); } diff --git a/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.config b/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.config new file mode 100644 index 0000000000..28c3becc98 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.config @@ -0,0 +1,123 @@ +//START OF CONFIG-LAST + + + + prefix:schema-service-singleton + yang-schema-service + + + prefix:hash-map-data-store + hash-map-data-store + + + prefix:dom-broker-impl + dom-broker + + dom:dom-data-store + ref_hash-map-data-store + + + + prefix:binding-broker-impl + binding-broker-impl + + binding:binding-notification-service + ref_binding-notification-broker + + + binding:binding-data-broker + ref_binding-data-broker + + + + prefix:runtime-generated-mapping + runtime-mapping-singleton + + + prefix:binding-notification-broker + binding-notification-broker + + + prefix:binding-data-broker + binding-data-broker + + dom:dom-broker-osgi-registry + ref_dom-broker + + + binding:binding-dom-mapping-service + ref_runtime-mapping-singleton + + + + + + dom:schema-service + + ref_yang-schema-service + /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] + + + + binding:binding-notification-service + + ref_binding-notification-broker + /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] + + + + dom:dom-data-store + + ref_hash-map-data-store + /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] + + + + binding:binding-broker-osgi-registry + + ref_binding-broker-impl + /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] + + + + binding-impl:binding-dom-mapping-service + + ref_runtime-mapping-singleton + /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] + + + + dom:dom-broker-osgi-registry + + ref_dom-broker + /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] + + + + binding:binding-data-broker + + ref_binding-data-broker + /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] + + + + + + +//END OF SNAPSHOT +urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 +urn:ietf:params:netconf:capability:candidate:1.0 +urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 +urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 +urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 +urn:ietf:params:netconf:capability:rollback-on-error:1.0 +urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 +urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 +urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 +urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 +//END OF CONFIG diff --git a/opendaylight/md-sal/sal-binding-it/src/test/resources/logback.xml b/opendaylight/md-sal/sal-binding-it/src/test/resources/logback.xml index 2d63ce5744..1d17796373 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/resources/logback.xml +++ b/opendaylight/md-sal/sal-binding-it/src/test/resources/logback.xml @@ -7,7 +7,10 @@ - + + + + diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java new file mode 100644 index 0000000000..f6efd57f06 --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java @@ -0,0 +1,12 @@ +package org.opendaylight.controller.md.sal.common.api; + +import java.util.EventListener; + +import org.opendaylight.yangtools.concepts.Registration; + +public interface RegistrationListener> extends EventListener { + + void onRegister(T registration); + + void onUnregister(T registration); +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java new file mode 100644 index 0000000000..85db5a0878 --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java @@ -0,0 +1,9 @@ +package org.opendaylight.controller.md.sal.common.api.data; + +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.concepts.Registration; + +public interface DataCommitHandlerRegistration

,D> extends Registration>{ + + P getPath(); +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java index 264d076b69..7d78fd283d 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java @@ -7,13 +7,17 @@ */ package org.opendaylight.controller.md.sal.common.api.data; -// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments. -// import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.controller.md.sal.common.api.RegistrationListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.concepts.Registration; -public interface DataProvisionService

*/, D> { +public interface DataProvisionService

, D> { public Registration> registerCommitHandler(P path, DataCommitHandler commitHandler); + + public ListenerRegistration>> + registerCommitHandlerListener(RegistrationListener> commitHandlerListener); } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java index c9e1d6e330..bee863321f 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java @@ -179,7 +179,7 @@ public abstract class AbstractDataModification

*/, D> imple if (operationalOriginal.containsKey(path)) { return true; } - D data = reader.readConfigurationData(path); + D data = reader.readOperationalData(path); if (data != null) { operationalOriginal.putIfAbsent(path, data); return true; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend index 74c4e0a148..e3d2b567a7 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend @@ -34,12 +34,18 @@ import java.util.Collection import com.google.common.collect.FluentIterable; import java.util.Set import com.google.common.collect.ImmutableList +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration +import org.opendaylight.controller.md.sal.common.api.RegistrationListener +import org.opendaylight.yangtools.concepts.util.ListenerRegistry +import java.util.concurrent.atomic.AtomicLong abstract class AbstractDataBroker

, D, DCL extends DataChangeListener> implements DataModificationTransactionFactory, // DataReader, // DataChangePublisher, // DataProvisionService { + private static val LOG = LoggerFactory.getLogger(AbstractDataBroker); + @Property var ExecutorService executor; @@ -47,17 +53,17 @@ DataProvisionService { var AbstractDataReadRouter dataReadRouter; Multimap> listeners = HashMultimap.create(); - Multimap> commitHandlers = HashMultimap.create(); - + Multimap> commitHandlers = HashMultimap.create(); + + val ListenerRegistry>> commitHandlerRegistrationListeners = new ListenerRegistry(); public new() { } protected def /*Iterator>,D>>*/ affectedCommitHandlers( HashSet

paths) { - return FluentIterable.from(commitHandlers.asMap.entrySet) - .filter[key.isAffectedBy(paths)] // - .transformAndConcat [value] // - .transform[instance].toList() + return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] // + .transformAndConcat[value] // + .transform[instance].toList() } override final readConfigurationData(P path) { @@ -69,8 +75,16 @@ DataProvisionService { } override final registerCommitHandler(P path, DataCommitHandler commitHandler) { - val registration = new DataCommitHandlerRegistration(path, commitHandler, this); + val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this); commitHandlers.put(path, registration) + LOG.info("Registering Commit Handler {} for path: {}",commitHandler,path); + for(listener : commitHandlerRegistrationListeners) { + try { + listener.instance.onRegister(registration); + } catch (Exception e) { + LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e); + } + } return registration; } @@ -87,13 +101,29 @@ DataProvisionService { return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg)); } + + override registerCommitHandlerListener(RegistrationListener> commitHandlerListener) { + val ret = commitHandlerRegistrationListeners.register(commitHandlerListener); + + return ret; + } + protected final def removeListener(DataChangeListenerRegistration registration) { listeners.remove(registration.path, registration); } - protected final def removeCommitHandler(DataCommitHandlerRegistration registration) { + protected final def removeCommitHandler(DataCommitHandlerRegistrationImpl registration) { commitHandlers.remove(registration.path, registration); + + LOG.info("Removing Commit Handler {} for path: {}",registration.instance,registration.path); + for(listener : commitHandlerRegistrationListeners) { + try { + listener.instance.onUnregister(registration); + } catch (Exception e) { + LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e); + } + } } protected final def getActiveCommitHandlers() { @@ -132,7 +162,7 @@ DataProvisionService { } @Data -package class ListenerStateCapture

, D,DCL extends DataChangeListener> { +package class ListenerStateCapture

, D, DCL extends DataChangeListener> { @Property P path; @@ -167,7 +197,9 @@ package class DataChangeListenerRegistration

, D, DCL extends D } -package class DataCommitHandlerRegistration

, D> extends AbstractObjectRegistration> { +package class DataCommitHandlerRegistrationImpl

, D> // +extends AbstractObjectRegistration> // +implements DataCommitHandlerRegistration { AbstractDataBroker dataBroker; @@ -184,10 +216,9 @@ package class DataCommitHandlerRegistration

, D> extends Abstra dataBroker.removeCommitHandler(this); dataBroker = null; } - } -package class TwoPhaseCommit

, D,DCL extends DataChangeListener> implements Callable> { +package class TwoPhaseCommit

, D, DCL extends DataChangeListener> implements Callable> { private static val log = LoggerFactory.getLogger(TwoPhaseCommit); @@ -214,15 +245,18 @@ package class TwoPhaseCommit

, D,DCL extends DataChangeListener val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths); + val transactionId = transaction.identifier; + + log.info("Transaction: {} Started.",transactionId); // requesting commits - val Iterable> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths); + val Iterable> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths); val List> handlerTransactions = new ArrayList(); try { for (handler : commitHandlers) { handlerTransactions.add(handler.requestCommit(transaction)); } } catch (Exception e) { - log.error("Request Commit failded", e); + log.error("Transaction: {} Request Commit failed", transactionId,e); return rollback(handlerTransactions, e); } val List> results = new ArrayList(); @@ -232,25 +266,25 @@ package class TwoPhaseCommit

, D,DCL extends DataChangeListener } listeners.publishDataChangeEvent(); } catch (Exception e) { - log.error("Finish Commit failed", e); + log.error("Transaction: {} Finish Commit failed",transactionId, e); return rollback(handlerTransactions, e); } - - + log.info("Transaction: {} Finished succesfully.",transactionId); return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet()); } - - def void publishDataChangeEvent(ImmutableList> listeners) { - for(listenerSet : listeners) { + + def void publishDataChangeEvent(ImmutableList> listeners) { + for (listenerSet : listeners) { val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path); val updatedOperational = dataBroker.readOperationalData(listenerSet.path); - - val changeEvent = new DataChangeEventImpl(transaction,listenerSet.initialConfigurationState,listenerSet.initialOperationalState,updatedOperational,updatedConfiguration); - for(listener : listenerSet.listeners) { + + val changeEvent = new DataChangeEventImpl(transaction, listenerSet.initialConfigurationState, + listenerSet.initialOperationalState, updatedOperational, updatedConfiguration); + for (listener : listenerSet.listeners) { try { listener.instance.onDataChanged(changeEvent); - + } catch (Exception e) { e.printStackTrace(); } @@ -267,6 +301,7 @@ package class TwoPhaseCommit

, D,DCL extends DataChangeListener return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet()); } } + public abstract class AbstractDataTransaction

, D> extends AbstractDataModification { @Property @@ -276,9 +311,9 @@ public abstract class AbstractDataTransaction

, D> extends Abst var AbstractDataBroker broker; - protected new(AbstractDataBroker dataBroker) { + protected new(Object identifier,AbstractDataBroker dataBroker) { super(dataBroker); - _identifier = new Object(); + _identifier = identifier; broker = dataBroker; status = TransactionStatus.NEW; diff --git a/opendaylight/md-sal/sal-dom-api/pom.xml b/opendaylight/md-sal/sal-dom-api/pom.xml index ca923f6baa..e52a7c302d 100644 --- a/opendaylight/md-sal/sal-dom-api/pom.xml +++ b/opendaylight/md-sal/sal-dom-api/pom.xml @@ -8,11 +8,73 @@ sal-core-api - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - + + + + org.apache.felix + maven-bundle-plugin + true + + + org.opendaylight.yangtools + yang-maven-plugin + 0.5.9-SNAPSHOT + + + + generate-sources + + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + + ${project.build.directory}/generated-sources/config + + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + 0.2.3-SNAPSHOT + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config + + + + + + + org.opendaylight.controller @@ -20,10 +82,14 @@ 1.0-SNAPSHOT + + org.opendaylight.controller + config-api + 0.2.3-SNAPSHOT + org.opendaylight.yangtools yang-data-api - 0.5.9-SNAPSHOT org.opendaylight.controller diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java new file mode 100644 index 0000000000..1062f5e535 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java @@ -0,0 +1,12 @@ +package org.opendaylight.controller.sal.core.api.data; + +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public interface DataStore extends // + DataReader, + DataCommitHandler { + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-common.yang b/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-common.yang new file mode 100644 index 0000000000..004574defa --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-common.yang @@ -0,0 +1,68 @@ +module opendaylight-md-sal-common { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:common"; + prefix "md-sal-common"; + + description + "Common definition for MD-SAL."; + + revision "2013-10-28" { + description + "Initial revision"; + } + + grouping rpc-routing-table { + + leaf routing-context { + type string; + } + list routes { + leaf path { + type string; + } + leaf destination { + type string; + } + } + + } + + grouping rpc-router { + leaf module { + type string; + } + container routing-tables { + list routing-table { + uses rpc-routing-table; + } + } + } + + grouping rpc-state { + list rpc-router { + uses rpc-router; + } + } + + grouping notification-state { + container notifications { + leaf published { + type uint32; + } + } + } + + grouping data-state { + container transactions { + leaf created { + type uint32; + } + leaf successful { + type uint32; + } + leaf failed { + type uint32; + } + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang b/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang new file mode 100644 index 0000000000..b0417eb8a0 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang @@ -0,0 +1,35 @@ +module opendaylight-md-sal-dom { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom"; + prefix "md-sal-dom"; + + import config { prefix config; revision-date 2013-04-05; } + + description + "Service definition for Binding Aware MD-SAL."; + + revision "2013-10-28" { + description + "Initial revision"; + } + + identity dom-broker-osgi-registry { + base "config:service-type"; + config:java-class "org.opendaylight.controller.sal.core.api.Broker"; + } + + identity dom-data-broker { + base "config:service-type"; + config:java-class "org.opendaylight.controller.sal.core.api.data.DataProviderService"; + } + + identity dom-data-store { + base "config:service-type"; + config:java-class "org.opendaylight.controller.sal.core.api.data.DataStore"; + } + + identity schema-service { + base "config:service-type"; + config:java-class "org.opendaylight.controller.sal.core.api.model.SchemaService"; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 62dbe16e41..14ab057398 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -72,6 +72,43 @@ + + org.opendaylight.yangtools + yang-maven-plugin + 0.5.9-SNAPSHOT + + + + generate-sources + + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + + ${project.build.directory}/generated-sources/config + + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + 0.2.3-SNAPSHOT + + + + + org.apache.felix maven-bundle-plugin @@ -79,13 +116,32 @@ ${project.groupId}.${project.artifactId} - org.opendaylight.controller.sal.dom.broker.BrokerActivator - org.opendaylight.controller.sal.dom.broker.* + org.opendaylight.controller.sal.dom.broker.*, + org.opendaylight.controller.config.yang.md.sal.dom.impl + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config + + + + + org.eclipse.xtend xtend-maven-plugin diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java new file mode 100644 index 0000000000..9a4fc6ddc1 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java @@ -0,0 +1,55 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: dom-broker-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:04:41 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator; +import org.opendaylight.controller.sal.dom.broker.BrokerImpl; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public final class DomBrokerImplModule extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractDomBrokerImplModule +{ + + private BundleContext bundleContext; + + public DomBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public DomBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, DomBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + // Add custom validation for module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + BrokerImpl broker = new BrokerImpl(); + BrokerConfigActivator activator = new BrokerConfigActivator(); + DataStore store = getDataStoreDependency(); + activator.start(broker, store,getBundleContext()); + return broker; + } + + private BundleContext getBundleContext() { + return this.bundleContext; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModuleFactory.java new file mode 100644 index 0000000000..8e9e9f6ac7 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModuleFactory.java @@ -0,0 +1,38 @@ +/** + * Generated file + + * Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: dom-broker-impl + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 20 17:04:41 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class DomBrokerImplModuleFactory extends + org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractDomBrokerImplModuleFactory { + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + DomBrokerImplModule module = (DomBrokerImplModule) super.createModule(instanceName, dependencyResolver, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + DomBrokerImplModule module = (DomBrokerImplModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModule.java new file mode 100644 index 0000000000..4bcbb08963 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModule.java @@ -0,0 +1,39 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: hash-map-data-store +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:01:31 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; + +/** +* +*/ +public final class HashMapDataStoreModule extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractHashMapDataStoreModule +{ + + public HashMapDataStoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public HashMapDataStoreModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, HashMapDataStoreModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate(){ + super.validate(); + // Add custom validation for module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + HashMapDataStore store = new HashMapDataStore(); + return store; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModuleFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModuleFactory.java new file mode 100644 index 0000000000..b9b6816a20 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/HashMapDataStoreModuleFactory.java @@ -0,0 +1,19 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: hash-map-data-store +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:01:31 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +/** +* +*/ +public class HashMapDataStoreModuleFactory extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractHashMapDataStoreModuleFactory +{ + + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java new file mode 100644 index 0000000000..6b597dea9e --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java @@ -0,0 +1,58 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: schema-service-singleton +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Nov 20 17:01:31 CET 2013 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import org.opendaylight.controller.sal.dom.broker.SchemaServiceImpl; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public final class SchemaServiceImplSingletonModule extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractSchemaServiceImplSingletonModule +{ + + BundleContext bundleContext; + + public SchemaServiceImplSingletonModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public SchemaServiceImplSingletonModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, SchemaServiceImplSingletonModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public boolean canReuseInstance(AbstractSchemaServiceImplSingletonModule oldModule) { + return true; + } + + public BundleContext getBundleContext() { + return bundleContext; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + @Override + public void validate(){ + super.validate(); + } + + @Override + public java.lang.AutoCloseable createInstance() { + SchemaServiceImpl newInstance = new SchemaServiceImpl(); + newInstance.setContext(getBundleContext()); + newInstance.setParser(new YangParserImpl()); + newInstance.start(); + return newInstance; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModuleFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModuleFactory.java new file mode 100644 index 0000000000..4b73656f72 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModuleFactory.java @@ -0,0 +1,46 @@ +/** + * Generated file + + * Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: schema-service-singleton + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Nov 20 17:01:31 CET 2013 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import java.util.Collections; +import java.util.Set; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DependencyResolverFactory; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class SchemaServiceImplSingletonModuleFactory extends + org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractSchemaServiceImplSingletonModuleFactory { + + private static final ModuleIdentifier IDENTIFIER = new ModuleIdentifier(NAME, "yang-schema-service"); + public static SchemaServiceImplSingletonModule SINGLETON; + + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + throw new UnsupportedOperationException("Only default instance supported."); + } + + @Override + public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, + BundleContext bundleContext) { + DependencyResolver dependencyResolver = dependencyResolverFactory.createDependencyResolver(IDENTIFIER); + + if (SINGLETON == null) { + SINGLETON = new SchemaServiceImplSingletonModule(IDENTIFIER, dependencyResolver); + SINGLETON.setBundleContext(bundleContext); + } + return Collections.singleton(SINGLETON); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java deleted file mode 100644 index 3af645a2b8..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerActivator.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.opendaylight.controller.sal.dom.broker; - -import java.util.Hashtable; - -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -import org.opendaylight.controller.sal.core.api.data.DataProviderService; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; -import org.opendaylight.controller.sal.core.api.mount.MountService; -import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -public class BrokerActivator implements BundleActivator { - - private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); - BrokerImpl broker; - private ServiceRegistration brokerReg; - private ServiceRegistration schemaReg; - private ServiceRegistration dataReg; - private ServiceRegistration dataProviderReg; - private SchemaServiceImpl schemaService; - private DataBrokerImpl dataService; - private MountPointManagerImpl mountService; - private ServiceRegistration mountReg; - private ServiceRegistration mountProviderReg; - private HashMapDataStore hashMapStore; - - @Override - public void start(BundleContext context) throws Exception { - Hashtable emptyProperties = new Hashtable(); - broker = new BrokerImpl(); - broker.setBundleContext(context); - - - schemaService = new SchemaServiceImpl(); - schemaService.setContext(context); - schemaService.setParser(new YangParserImpl()); - schemaService.start(); - schemaReg = context.registerService(SchemaService.class, schemaService, new Hashtable()); - - dataService = new DataBrokerImpl(); - dataService.setExecutor(broker.getExecutor()); - - dataReg = context.registerService(DataBrokerService.class, dataService, emptyProperties); - dataProviderReg = context.registerService(DataProviderService.class, dataService, emptyProperties); - - hashMapStore = new HashMapDataStore(); - - dataService.registerConfigurationReader(ROOT, hashMapStore); - dataService.registerCommitHandler(ROOT, hashMapStore); - dataService.registerOperationalReader(ROOT, hashMapStore); - - mountService = new MountPointManagerImpl(); - mountService.setDataBroker(dataService); - - mountReg = context.registerService(MountService.class, mountService, emptyProperties); - mountProviderReg = context.registerService(MountProvisionService.class, mountService, emptyProperties); - - brokerReg = context.registerService(Broker.class, broker, emptyProperties); - } - - @Override - public void stop(BundleContext context) throws Exception { - if (brokerReg != null) { - brokerReg.unregister(); - } - } -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend new file mode 100644 index 0000000000..a6aa0ce32e --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -0,0 +1,67 @@ +package org.opendaylight.controller.sal.dom.broker + +import org.osgi.framework.ServiceRegistration +import org.opendaylight.controller.sal.core.api.model.SchemaService +import org.opendaylight.controller.sal.core.api.data.DataBrokerService +import org.opendaylight.controller.sal.core.api.data.DataProviderService +import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore +import org.opendaylight.controller.sal.core.api.mount.MountProvisionService +import org.opendaylight.controller.sal.core.api.mount.MountService +import org.osgi.framework.BundleContext +import java.util.Hashtable +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import org.opendaylight.controller.sal.core.api.data.DataStore + +class BrokerConfigActivator implements AutoCloseable { + + + private static val ROOT = InstanceIdentifier.builder().toInstance(); + + private var ServiceRegistration schemaReg; + private var ServiceRegistration dataReg; + private var ServiceRegistration dataProviderReg; + private var ServiceRegistration mountReg; + private var ServiceRegistration mountProviderReg; + + private var SchemaServiceImpl schemaService; + private var DataBrokerImpl dataService; + private var MountPointManagerImpl mountService; + + public def void start(BrokerImpl broker,DataStore store,BundleContext context) { + val emptyProperties = new Hashtable(); + broker.setBundleContext(context); + + + schemaService = new SchemaServiceImpl(); + schemaService.setContext(context); + schemaService.setParser(new YangParserImpl()); + schemaService.start(); + schemaReg = context.registerService(SchemaService, schemaService, emptyProperties); + + dataService = new DataBrokerImpl(); + dataService.setExecutor(broker.getExecutor()); + + dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); + dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); + + dataService.registerConfigurationReader(ROOT, store); + dataService.registerCommitHandler(ROOT, store); + dataService.registerOperationalReader(ROOT, store); + + mountService = new MountPointManagerImpl(); + mountService.setDataBroker(dataService); + + mountReg = context.registerService(MountService, mountService, emptyProperties); + mountProviderReg = context.registerService(MountProvisionService, mountService, emptyProperties); + } + + override def close() { + schemaReg?.unregister(); + dataReg?.unregister(); + dataProviderReg?.unregister(); + mountReg?.unregister(); + mountProviderReg?.unregister(); + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 26fecef688..7ef594bad9 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -30,7 +30,7 @@ import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener -public class BrokerImpl implements Broker { +public class BrokerImpl implements Broker, AutoCloseable { private static val log = LoggerFactory.getLogger(BrokerImpl); // Broker Generic Context @@ -43,6 +43,9 @@ public class BrokerImpl implements Broker { private var ExecutorService executor = Executors.newFixedThreadPool(5); @Property private var BundleContext bundleContext; + + @Property + private var AutoCloseable deactivator; @Property private var RpcRouter router; @@ -107,4 +110,9 @@ public class BrokerImpl implements Broker { sessions.remove(consumerContextImpl); providerSessions.remove(consumerContextImpl); } + + override close() throws Exception { + deactivator?.close(); + } + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java index d95fdcc53d..1197ef34bd 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java @@ -1,5 +1,7 @@ package org.opendaylight.controller.sal.dom.broker; +import java.util.concurrent.atomic.AtomicLong; + import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; import org.opendaylight.controller.sal.common.DataStoreIdentifier; @@ -18,9 +20,12 @@ public class DataBrokerImpl extends AbstractDataBroker>> registerCommitHandlerListener( + RegistrationListener> commitHandlerListener) { + // TODO Auto-generated method stub + return null; + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java index ba558c51fd..531f9e86c2 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java @@ -13,6 +13,8 @@ import java.util.zip.Checksum; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.osgi.util.tracker.BundleTracker; import org.osgi.util.tracker.BundleTrackerCustomizer; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; @@ -20,6 +22,7 @@ import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; +import org.osgi.framework.ServiceReference; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.controller.sal.core.api.model.SchemaService; @@ -34,9 +37,13 @@ import com.google.common.collect.Collections2; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; + import static com.google.common.base.Preconditions.*; -public class SchemaServiceImpl implements SchemaService, AutoCloseable { +public class SchemaServiceImpl implements // +SchemaService, // +ServiceTrackerCustomizer, // +AutoCloseable { private static final Logger logger = LoggerFactory.getLogger(SchemaServiceImpl.class); private ListenerRegistry listeners; @@ -54,6 +61,8 @@ public class SchemaServiceImpl implements SchemaService, AutoCloseable { private BundleTracker bundleTracker; private final YangStoreCache cache = new YangStoreCache(); + private ServiceTracker listenerTracker; + public ListenerRegistry getListeners() { return listeners; } @@ -84,9 +93,11 @@ public class SchemaServiceImpl implements SchemaService, AutoCloseable { if (listeners == null) { listeners = new ListenerRegistry<>(); } - + + listenerTracker = new ServiceTracker<>(context, SchemaServiceListener.class, this); bundleTracker = new BundleTracker(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner); bundleTracker.open(); + listenerTracker.open(); } public SchemaContext getGlobalContext() { @@ -185,6 +196,18 @@ public class SchemaServiceImpl implements SchemaService, AutoCloseable { private void updateCache(SchemaContext snapshot) { cache.cacheYangStore(consistentBundlesToYangURLs, snapshot); + + Object[] services = listenerTracker.getServices(); + if(services != null) { + for(Object rawListener : services) { + SchemaServiceListener listener = (SchemaServiceListener) rawListener; + try { + listener.onGlobalContextUpdated(snapshot); + } catch (Exception e) { + logger.error("Exception occured during invoking listener",e); + } + } + } for (ListenerRegistration listener : listeners) { try { listener.getInstance().onGlobalContextUpdated(snapshot); @@ -220,6 +243,7 @@ public class SchemaServiceImpl implements SchemaService, AutoCloseable { proposedNewState.putAll(inconsistentBundlesToYangURLs); proposedNewState.putAll(bundle, addedURLs); boolean adding = true; + if (tryToUpdateState(addedURLs, proposedNewState, adding) == false) { inconsistentBundlesToYangURLs.putAll(bundle, addedURLs); } @@ -276,6 +300,26 @@ public class SchemaServiceImpl implements SchemaService, AutoCloseable { this.cachedUrls = setFromMultimapValues(urls); this.cachedContextSnapshot = ctx; } - + } + + @Override + public SchemaServiceListener addingService(ServiceReference reference) { + + SchemaServiceListener listener = context.getService(reference); + SchemaContext _ctxContext = getGlobalContext(); + if(getContext() != null) { + listener.onGlobalContextUpdated(_ctxContext); + } + return listener; + } + + @Override + public void modifiedService(ServiceReference reference, SchemaServiceListener service) { + // NOOP + } + + @Override + public void removedService(ServiceReference reference, SchemaServiceListener service) { + context.ungetService(reference); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend index 7d57819cbf..e7445e6965 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend @@ -1,7 +1,5 @@ package org.opendaylight.controller.sal.dom.broker.impl -import org.opendaylight.controller.md.sal.common.api.data.DataReader -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler import org.opendaylight.controller.md.sal.common.api.data.DataModification import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction import org.opendaylight.yangtools.yang.common.RpcResult @@ -12,10 +10,10 @@ import java.util.Collections import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.CompositeNode import static extension org.opendaylight.controller.sal.dom.broker.impl.DataUtils.*; +import org.opendaylight.controller.sal.core.api.data.DataStore +import java.util.HashSet -class HashMapDataStore // -implements // -DataReader, DataCommitHandler { +class HashMapDataStore implements DataStore, AutoCloseable { val Map configuration = new ConcurrentHashMap(); val Map operational = new ConcurrentHashMap(); @@ -45,14 +43,32 @@ DataReader, DataCommitHandler map, InstanceIdentifier identifier) { + val affected = new HashSet(); + for(path : map.keySet) { + if(identifier.contains(path)) { + affected.add(path); + } + } + for(pathToRemove : affected) { + map.remove(pathToRemove); + } + + } + + override close() { + // NOOP + } + } class HashMapDataStoreTransaction implements // diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java index 2fded87981..329219ebb0 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataProviderServiceProxy.java @@ -1,6 +1,8 @@ package org.opendaylight.controller.sal.dom.broker.osgi; +import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.sal.common.DataStoreIdentifier; import org.opendaylight.controller.sal.core.api.data.DataChangeListener; @@ -74,4 +76,10 @@ public class DataProviderServiceProxy extends AbstractBrokerServiceProxy>> registerCommitHandlerListener( + RegistrationListener> commitHandlerListener) { + return addRegistration(getDelegate().registerCommitHandlerListener(commitHandlerListener)); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang b/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang new file mode 100644 index 0000000000..bf12ac4f01 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang @@ -0,0 +1,61 @@ +module opendaylight-sal-dom-broker-impl { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl"; + prefix "binding-impl"; + + import config { prefix config; revision-date 2013-04-05; } + import opendaylight-md-sal-dom {prefix sal;} + + description + "Service definition for Binding Aware MD-SAL."; + + revision "2013-10-28" { + description + "Initial revision"; + } + + identity dom-broker-impl { + base config:module-type; + config:provided-service sal:dom-broker-osgi-registry; + config:java-name-prefix DomBrokerImpl; + } + + identity hash-map-data-store { + base config:module-type; + config:provided-service sal:dom-data-store; + config:java-name-prefix HashMapDataStore; + } + + identity schema-service-singleton { + base config:module-type; + config:provided-service sal:schema-service; + config:java-name-prefix SchemaServiceImplSingleton; + } + + augment "/config:modules/config:module/config:configuration" { + case dom-broker-impl { + when "/config:modules/config:module/config:type = 'dom-broker-impl'"; + container data-store { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity sal:dom-data-store; + } + } + } + } + } + + augment "/config:modules/config:module/config:state" { + case hash-map-data-store { + when "/config:modules/config:module/config:type = 'hash-map-data-store'"; + } + } + + augment "/config:modules/config:module/config:state" { + case schema-service-singleton { + when "/config:modules/config:module/config:type = 'schema-service-singleton'"; + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index c36a79c5d9..a22ea62397 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -15,10 +15,9 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.StructuredData; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; /** @@ -57,7 +56,6 @@ public interface RestconfService extends RestconfServiceLegacy { @GET public Object getRoot(); - @GET @Path("/modules") @Produces({API+JSON,API+XML}) @@ -68,23 +66,20 @@ public interface RestconfService extends RestconfServiceLegacy { @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML,API+JSON,API+XML}) public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload); - @GET @Path("/config/{identifier:.+}") @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML}) public StructuredData readConfigurationData(@PathParam("identifier") String identifier); - - @PUT @Path("/config/{identifier:.+}") @Produces({API+JSON,API+XML}) - public RpcResult createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload); + public Response createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/config/{identifier:.+}") @Produces({API+JSON,API+XML}) - public RpcResult updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload); + public Response updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload); @GET @Path("/operational/{identifier:.+}") @@ -94,12 +89,11 @@ public interface RestconfService extends RestconfServiceLegacy { @PUT @Path("/operational/{identifier:.+}") @Produces({API+JSON,API+XML}) - public RpcResult createOperationalData(@PathParam("identifier") String identifier, CompositeNode payload); + public Response createOperationalData(@PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/operational/{identifier:.+}") @Produces({API+JSON,API+XML}) - public RpcResult updateOperationalData(@PathParam("identifier") String identifier, CompositeNode payload); + public Response updateOperationalData(@PathParam("identifier") String identifier, CompositeNode payload); - } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java index 6683fd1835..242e7f3150 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java @@ -8,10 +8,9 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.StructuredData; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; public interface RestconfServiceLegacy { @@ -35,12 +34,12 @@ public interface RestconfServiceLegacy { @PUT @Path("/datastore/{identifier:.+}") @Produces({API+JSON,API+XML}) - public RpcResult createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload); + public Response createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload); @Deprecated @POST @Path("/datastore/{identifier:.+}") @Produces({API+JSON,API+XML}) - public RpcResult updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload); + public Response updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java index 5a1b42fd80..073b24e033 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java @@ -3,70 +3,58 @@ package org.opendaylight.controller.sal.rest.impl; import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import javax.activation.UnsupportedDataTypeException; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.SimpleNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition; -import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.type.*; import com.google.common.base.Preconditions; import com.google.gson.stream.JsonWriter; class JsonMapper { - + private final Set foundLeafLists = new HashSet<>(); private final Set foundLists = new HashSet<>(); - + public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException { Preconditions.checkNotNull(writer); Preconditions.checkNotNull(data); Preconditions.checkNotNull(schema); writer.beginObject(); - + if (schema instanceof ContainerSchemaNode) { writeContainer(writer, data, (ContainerSchemaNode) schema); } else if (schema instanceof ListSchemaNode) { - writeList(writer, data, (ListSchemaNode) schema); + writeList(writer, null, data, (ListSchemaNode) schema); } else { throw new UnsupportedDataTypeException( "Schema can be ContainerSchemaNode or ListSchemaNode. Other types are not supported yet."); } - + writer.endObject(); - + foundLeafLists.clear(); foundLists.clear(); } - private void writeChildrenOfParent(JsonWriter writer, CompositeNode parent, DataNodeContainer parentSchema) throws IOException { + private void writeChildrenOfParent(JsonWriter writer, CompositeNode parent, DataNodeContainer parentSchema) + throws IOException { checkNotNull(parent); checkNotNull(parentSchema); - + for (Node child : parent.getChildren()) { DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes()); if (childSchema == null) { throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName() + "\" is not conform to schema"); } - + if (childSchema instanceof ContainerSchemaNode) { Preconditions.checkState(child instanceof CompositeNode, "Data representation of Container should be CompositeNode - " + child.getNodeType()); @@ -76,14 +64,14 @@ class JsonMapper { Preconditions.checkState(child instanceof CompositeNode, "Data representation of List should be CompositeNode - " + child.getNodeType()); foundLists.add((ListSchemaNode) childSchema); - writeList(writer, (CompositeNode) child, (ListSchemaNode) childSchema); + writeList(writer, parent, (CompositeNode) child, (ListSchemaNode) childSchema); } } else if (childSchema instanceof LeafListSchemaNode) { if (!foundLeafLists.contains(childSchema)) { Preconditions.checkState(child instanceof SimpleNode, "Data representation of LeafList should be SimpleNode - " + child.getNodeType()); foundLeafLists.add((LeafListSchemaNode) childSchema); - writeLeafList(writer, (SimpleNode) child, (LeafListSchemaNode) childSchema); + writeLeafList(writer, parent, (SimpleNode) child, (LeafListSchemaNode) childSchema); } } else if (childSchema instanceof LeafSchemaNode) { Preconditions.checkState(child instanceof SimpleNode, @@ -94,7 +82,7 @@ class JsonMapper { + "LeafListSchemaNode, or LeafSchemaNode. Other types are not supported yet."); } } - + for (Node child : parent.getChildren()) { DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes()); if (childSchema instanceof LeafListSchemaNode) { @@ -104,7 +92,7 @@ class JsonMapper { } } } - + private DataSchemaNode findFirstSchemaForNode(Node node, Set dataSchemaNode) { for (DataSchemaNode dsn : dataSchemaNode) { if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) { @@ -113,84 +101,154 @@ class JsonMapper { } return null; } - + private void writeContainer(JsonWriter writer, CompositeNode node, ContainerSchemaNode schema) throws IOException { writer.name(node.getNodeType().getLocalName()); writer.beginObject(); writeChildrenOfParent(writer, node, schema); writer.endObject(); } - - private void writeList(JsonWriter writer, CompositeNode node, ListSchemaNode schema) throws IOException { - writer.name(node.getNodeType().getLocalName()); - writer.beginArray(); - - if (node.getParent() != null) { - CompositeNode parent = node.getParent(); - List nodeLists = parent.getCompositesByName(node.getNodeType()); - for (CompositeNode nodeList : nodeLists) { - writer.beginObject(); - writeChildrenOfParent(writer, nodeList, schema); - writer.endObject(); - } - } else { + + private void writeList(JsonWriter writer, CompositeNode nodeParent, CompositeNode node, ListSchemaNode schema) throws IOException { + writer.name(node.getNodeType().getLocalName()); + writer.beginArray(); + + if (nodeParent != null) { + List nodeLists = nodeParent.getCompositesByName(node.getNodeType()); + for (CompositeNode nodeList : nodeLists) { writer.beginObject(); - writeChildrenOfParent(writer, node, schema); + writeChildrenOfParent(writer, nodeList, schema); writer.endObject(); } - - writer.endArray(); - } - - private void writeLeafList(JsonWriter writer, SimpleNode node, LeafListSchemaNode schema) throws IOException { - writer.name(node.getNodeType().getLocalName()); - writer.beginArray(); - - CompositeNode parent = node.getParent(); - List> nodeLeafLists = parent.getSimpleNodesByName(node.getNodeType()); - for (SimpleNode nodeLeafList : nodeLeafLists) { - writeValueOfNodeByType(writer, nodeLeafList, schema.getType()); - } - - writer.endArray(); + } else { + writer.beginObject(); + writeChildrenOfParent(writer, node, schema); + writer.endObject(); + } + + writer.endArray(); } - + + private void writeLeafList(JsonWriter writer, CompositeNode nodeParent, SimpleNode node, LeafListSchemaNode schema) throws IOException { + writer.name(node.getNodeType().getLocalName()); + writer.beginArray(); + + List> nodeLeafLists = nodeParent.getSimpleNodesByName(node.getNodeType()); + for (SimpleNode nodeLeafList : nodeLeafLists) { + writeValueOfNodeByType(writer, nodeLeafList, schema.getType()); + } + + writer.endArray(); + } + private void writeLeaf(JsonWriter writer, SimpleNode node, LeafSchemaNode schema) throws IOException { writer.name(node.getNodeType().getLocalName()); writeValueOfNodeByType(writer, node, schema.getType()); } - - private void writeValueOfNodeByType(JsonWriter writer, SimpleNode node, TypeDefinition type) throws IOException { + + private void writeValueOfNodeByType(JsonWriter writer, SimpleNode node, TypeDefinition type) + throws IOException { if (!(node.getValue() instanceof String)) { throw new IllegalStateException("Value in SimpleNode should be type String"); } - + String value = (String) node.getValue(); - // TODO check Leafref, InstanceIdentifierTypeDefinition, IdentityrefTypeDefinition, UnionTypeDefinition - if (type.getBaseType() != null) { - writeValueOfNodeByType(writer, node, type.getBaseType()); - } else if (type instanceof InstanceIdentifierTypeDefinition) { - writer.value(((InstanceIdentifierTypeDefinition) type).getPathStatement().toString()); - } else if (type instanceof DecimalTypeDefinition - || type instanceof IntegerTypeDefinition - || type instanceof UnsignedIntegerTypeDefinition) { + // TODO check Leafref, InstanceIdentifierTypeDefinition, + // IdentityrefTypeDefinition, UnionTypeDefinition + TypeDefinition baseType = resolveBaseTypeFrom(type); + if (baseType instanceof InstanceIdentifierTypeDefinition) { + writer.value(((InstanceIdentifierTypeDefinition) baseType).getPathStatement().toString()); + } else if (baseType instanceof UnionTypeDefinition) { + processTypeIsUnionType(writer, (UnionTypeDefinition) baseType, value); + } else if (baseType instanceof DecimalTypeDefinition || baseType instanceof IntegerTypeDefinition + || baseType instanceof UnsignedIntegerTypeDefinition) { writer.value(new NumberForJsonWriter(value)); - } else if (type instanceof BooleanTypeDefinition) { + } else if (baseType instanceof BooleanTypeDefinition) { writer.value(Boolean.parseBoolean(value)); - } else if (type instanceof EmptyTypeDefinition) { - writer.beginArray(); - writer.nullValue(); - writer.endArray(); + } else if (baseType instanceof EmptyTypeDefinition) { + writeEmptyDataTypeToJson(writer); } else { writer.value(value != null ? value : ""); } } - + + private void processTypeIsUnionType(JsonWriter writer, UnionTypeDefinition unionType, String value) + throws IOException { + if (value == null) { + writeEmptyDataTypeToJson(writer); + } else if ((isNumber(value)) + && containsType(unionType, UnsignedIntegerTypeDefinition.class, IntegerTypeDefinition.class, + DecimalTypeDefinition.class)) { + writer.value(new NumberForJsonWriter(value)); + } else if (isBoolean(value) && containsType(unionType, BooleanTypeDefinition.class)) { + writer.value(Boolean.parseBoolean(value)); + } else { + writer.value(value); + } + } + + private boolean isBoolean(String value) { + if (value.equals("true") || value.equals("false")) { + return true; + } + return false; + } + + private void writeEmptyDataTypeToJson(JsonWriter writer) throws IOException { + writer.beginArray(); + writer.nullValue(); + writer.endArray(); + } + + private boolean isNumber(String value) { + try { + Double.valueOf(value); + } catch (NumberFormatException e) { + return false; + } + return true; + } + + private boolean containsType(UnionTypeDefinition unionType, Class... searchedTypes) { + List> allUnionSubtypes = resolveAllUnionSubtypesFrom(unionType); + + for (TypeDefinition unionSubtype : allUnionSubtypes) { + for (Class searchedType : searchedTypes) { + if (searchedType.isInstance(unionSubtype)) { + return true; + } + } + } + return false; + } + + private List> resolveAllUnionSubtypesFrom(UnionTypeDefinition inputType) { + List> result = new ArrayList<>(); + for (TypeDefinition subtype : inputType.getTypes()) { + TypeDefinition resolvedSubtype = subtype; + + resolvedSubtype = resolveBaseTypeFrom(subtype); + + if (resolvedSubtype instanceof UnionTypeDefinition) { + List> subtypesFromRecursion = resolveAllUnionSubtypesFrom((UnionTypeDefinition) resolvedSubtype); + result.addAll(subtypesFromRecursion); + } else { + result.add(resolvedSubtype); + } + } + + return result; + } + + private TypeDefinition resolveBaseTypeFrom(TypeDefinition type) { + return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type; + } + private static final class NumberForJsonWriter extends Number { - + private static final long serialVersionUID = -3147729419814417666L; private final String value; - + public NumberForJsonWriter(String value) { this.value = value; } @@ -219,7 +277,7 @@ class JsonMapper { public String toString() { return value; } - + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java index a0acaf156f..a2ae1c9f7f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java @@ -19,12 +19,12 @@ class JsonReader { public CompositeNodeWrapper read(InputStream entityStream) throws UnsupportedFormatException { JsonParser parser = new JsonParser(); - + JsonElement rootElement = parser.parse(new InputStreamReader(entityStream)); if (!rootElement.isJsonObject()) { throw new UnsupportedFormatException("Root element of Json has to be Object"); } - + Set> entrySetsOfRootJsonObject = rootElement.getAsJsonObject().entrySet(); if (entrySetsOfRootJsonObject.size() != 1) { throw new UnsupportedFormatException("Json Object should contain one element"); @@ -41,13 +41,15 @@ class JsonReader { if (firstElementInArray.isJsonObject()) { return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject()); } - throw new UnsupportedFormatException("Array as the first element in Json Object can have only Object element"); + throw new UnsupportedFormatException( + "Array as the first element in Json Object can have only Object element"); } } - throw new UnsupportedFormatException("First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."); + throw new UnsupportedFormatException( + "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet."); } } - + private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) { CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFrom(rootObjectName), getLocalNameFrom(rootObjectName)); @@ -56,7 +58,7 @@ class JsonReader { } return firstNode; } - + private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) { if (childType.isJsonObject()) { CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFrom(childName), @@ -66,19 +68,18 @@ class JsonReader { addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child); } } else if (childType.isJsonArray()) { - for (JsonElement childOfChildType : childType.getAsJsonArray()) { - addChildToParent(childName, childOfChildType, parent); + if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) { + parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), null)); + + } else { + for (JsonElement childOfChildType : childType.getAsJsonArray()) { + addChildToParent(childName, childOfChildType, parent); + } } } else if (childType.isJsonPrimitive()) { JsonPrimitive childPrimitive = childType.getAsJsonPrimitive(); String value = childPrimitive.getAsString(); - SimpleNodeWrapper child = null; - if (value.equals("[null]")) { - child = new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), null); - } else { - child = new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value); - } - parent.addValue(child); + parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java index 9f31eb46d5..bf7ff7d435 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java @@ -18,13 +18,13 @@ import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; public class XmlReader { - + private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); private XMLEventReader eventReader; public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException { eventReader = xmlInputFactory.createXMLEventReader(entityStream); - + if (eventReader.hasNext()) { XMLEvent element = eventReader.peek(); if (element.isStartDocument()) { @@ -35,7 +35,7 @@ public class XmlReader { if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) { throw new UnsupportedFormatException("Root element of XML has to be composite element."); } - + final Stack> processingQueue = new Stack<>(); CompositeNodeWrapper root = null; NodeWrapper element = null; @@ -73,14 +73,14 @@ public class XmlReader { element = processingQueue.pop(); } } - + if (!root.getLocalName().equals(element.getLocalName())) { throw new UnsupportedFormatException("XML should contain only one root element"); } - + return root; } - + private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException { checkArgument(event != null, "XML Event cannot be NULL!"); if (event.isStartElement()) { @@ -99,7 +99,7 @@ public class XmlReader { } return false; } - + private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException { checkArgument(event != null, "XML Event cannot be NULL!"); if (event.isStartElement()) { @@ -120,8 +120,9 @@ public class XmlReader { } return false; } - - private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final StartElement startElement) throws XMLStreamException { + + private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final StartElement startElement) + throws XMLStreamException { checkArgument(startElement != null, "Start Element cannot be NULL!"); String data = null; @@ -133,25 +134,29 @@ public class XmlReader { data = innerEvent.asCharacters().getData(); } } else if (innerEvent.isEndElement()) { - data = ""; + if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) { + data = null; + } else { + data = ""; + } } } - + return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data); } - + private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) { checkArgument(startElement != null, "Start Element cannot be NULL!"); return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement)); } - + private String getLocalNameFrom(StartElement startElement) { return startElement.getName().getLocalPart(); } - + private URI getNamespaceFrom(StartElement startElement) { String namespaceURI = startElement.getName().getNamespaceURI(); return namespaceURI.isEmpty() ? null : URI.create(namespaceURI); } - + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend index f5b9132532..eb1f6165ca 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend @@ -22,7 +22,7 @@ class BrokerFacade implements DataReader { private DataBrokerService dataService; private new() { - if (INSTANCE != null) { + if (INSTANCE !== null) { throw new IllegalStateException("Already instantiated"); } } @@ -32,7 +32,7 @@ class BrokerFacade implements DataReader { } private def void checkPreconditions() { - if (context == null || dataService == null) { + if (context === null || dataService === null) { throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE) .entity(RestconfProvider::NOT_INITALIZED_MSG).build()) } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index c1ee611e07..c2b0ae8bdb 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -46,7 +46,7 @@ class ControllerContext implements SchemaServiceListener { private new() { - if (INSTANCE != null) { + if (INSTANCE !== null) { throw new IllegalStateException("Already instantiated"); } } @@ -56,7 +56,7 @@ class ControllerContext implements SchemaServiceListener { } private def void checkPreconditions() { - if (schemas == null) { + if (schemas === null) { throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE) .entity(RestconfProvider::NOT_INITALIZED_MSG).build()) } @@ -72,7 +72,7 @@ class ControllerContext implements SchemaServiceListener { pathArgs.remove(0) } val schemaNode = ret.collectPathArguments(pathArgs, restconfInstance.findModule); - if (schemaNode == null) { + if (schemaNode === null) { return null } new InstanceIdWithSchemaNode(ret.toInstance, schemaNode) @@ -92,7 +92,7 @@ class ControllerContext implements SchemaServiceListener { private def getLatestModule(SchemaContext schema, String moduleName) { checkNotNull(schema) - checkArgument(moduleName != null && !moduleName.empty) + checkArgument(moduleName !== null && !moduleName.empty) val modules = schema.modules.filter[m|m.name == moduleName] var latestModule = modules.head for (module : modules) { @@ -134,9 +134,9 @@ class ControllerContext implements SchemaServiceListener { def CharSequence toRestconfIdentifier(QName qname) { checkPreconditions var module = uriToModuleName.get(qname.namespace) - if (module == null) { + if (module === null) { val moduleSchema = schemas.findModuleByNamespaceAndRevision(qname.namespace, qname.revision); - if(moduleSchema == null) throw new IllegalArgumentException() + if(moduleSchema === null) throw new IllegalArgumentException() uriToModuleName.put(qname.namespace, moduleSchema.name) module = moduleSchema.name; } @@ -189,7 +189,7 @@ class ControllerContext implements SchemaServiceListener { } private def toUriString(Object object) { - if(object == null) return ""; + if(object === null) return ""; return URLEncoder.encode(object.toString) } @@ -203,14 +203,14 @@ class ControllerContext implements SchemaServiceListener { val nodeName = nodeRef.toNodeName(); val targetNode = parentNode.getDataChildByName(nodeName); - if (targetNode == null) { + if (targetNode === null) { val children = parentNode.childNodes for (child : children) { if (child instanceof ChoiceNode) { val choice = child as ChoiceNode for (caze : choice.cases) { val result = builder.collectPathArguments(strings, caze as DataNodeContainer); - if (result != null) + if (result !== null) return result } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend index a41a48287d..a4587fa787 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend @@ -1,10 +1,13 @@ package org.opendaylight.controller.sal.restconf.impl import java.util.List +import javax.ws.rs.core.Response import org.opendaylight.controller.sal.rest.api.RestconfService import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.yangtools.yang.model.api.DataNodeContainer import org.opendaylight.yangtools.yang.model.api.DataSchemaNode +import org.opendaylight.controller.md.sal.common.api.TransactionStatus +import javax.ws.rs.WebApplicationException class RestconfImpl implements RestconfService { @@ -17,7 +20,7 @@ class RestconfImpl implements RestconfService { extension ControllerContext controllerContext private new() { - if (INSTANCE != null) { + if (INSTANCE !== null) { throw new IllegalStateException("Already instantiated"); } } @@ -40,21 +43,29 @@ class RestconfImpl implements RestconfService { } override readData(String identifier) { - val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier + val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier); return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode) } override createConfigurationData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) - return broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + switch status.result { + case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build + default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build + } } override updateConfigurationData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) - return broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + val status = broker.commitConfigurationDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + switch status.result { + case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build + default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build + } } override invokeRpc(String identifier, CompositeNode payload) { @@ -66,13 +77,13 @@ class RestconfImpl implements RestconfService { } override readConfigurationData(String identifier) { - val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier + val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier); return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode) } override readOperationalData(String identifier) { - val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier + val instanceIdentifierWithSchemaNode = identifier.resolveInstanceIdentifier val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier); return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode) } @@ -86,15 +97,32 @@ class RestconfImpl implements RestconfService { } override createOperationalData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) - return broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + val status = broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + switch status.result { + case TransactionStatus.COMMITED: Response.status(Response.Status.OK).build + default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build + } } override updateOperationalData(String identifier, CompositeNode payload) { - val identifierWithSchemaNode = identifier.toInstanceIdentifier + val identifierWithSchemaNode = identifier.resolveInstanceIdentifier val value = resolveNodeNamespaceBySchema(payload, identifierWithSchemaNode.schemaNode) - return broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + val status = broker.commitOperationalDataPut(identifierWithSchemaNode.instanceIdentifier,value).get(); + switch status.result { + case TransactionStatus.COMMITED: Response.status(Response.Status.NO_CONTENT).build + default: Response.status(Response.Status.INTERNAL_SERVER_ERROR).build + } + } + + private def InstanceIdWithSchemaNode resolveInstanceIdentifier(String identifier) { + val identifierWithSchemaNode = identifier.toInstanceIdentifier + if (identifierWithSchemaNode === null) { + throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity("URI has bad format") + .build()); + } + return identifierWithSchemaNode } private def CompositeNode resolveNodeNamespaceBySchema(CompositeNode node, DataSchemaNode schema) { @@ -106,7 +134,7 @@ class RestconfImpl implements RestconfService { } private def void addNamespaceToNodeFromSchemaRecursively(NodeWrapper nodeBuilder, DataSchemaNode schema) { - if (nodeBuilder.namespace == null) { + if (nodeBuilder.namespace === null) { nodeBuilder.namespace = schema.QName.namespace } if (nodeBuilder instanceof CompositeNodeWrapper) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java index a32a3479ba..251b212513 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java @@ -6,30 +6,85 @@ import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.yangtools.yang.common.RpcResult; public class DummyFuture implements Future> { + + private final boolean cancel; + private final boolean isCancelled; + private final boolean isDone; + private final RpcResult result; + + public DummyFuture() { + cancel = false; + isCancelled = false; + isDone = false; + result = null; + } + + private DummyFuture(Builder builder) { + cancel = builder.cancel; + isCancelled = builder.isCancelled; + isDone = builder.isDone; + result = builder.result; + } + + public static Builder builder() { + return new DummyFuture.Builder(); + } @Override public boolean cancel(boolean mayInterruptIfRunning) { - return false; + return cancel; } @Override public boolean isCancelled() { - return false; + return isCancelled; } @Override public boolean isDone() { - return false; + return isDone; } @Override public RpcResult get() throws InterruptedException, ExecutionException { - return null; + return result; } @Override public RpcResult get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return null; + return result; + } + + public static class Builder { + + private boolean cancel; + private boolean isCancelled; + private boolean isDone; + private RpcResult result; + + public Builder cancel(boolean cancel) { + this.cancel = cancel; + return this; + } + + public Builder isCancelled(boolean isCancelled) { + this.isCancelled = isCancelled; + return this; + } + + public Builder isDone(boolean isDone) { + this.isDone = isDone; + return this; + } + + public Builder rpcResult(RpcResult result) { + this.result = result; + return this; + } + + public Future> build() { + return new DummyFuture(this); + } } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java new file mode 100644 index 0000000000..5ab4f99fdc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java @@ -0,0 +1,72 @@ +package org.opendaylight.controller.sal.restconf.impl.test; + +import java.util.Collection; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class DummyRpcResult implements RpcResult { + + private final boolean isSuccessful; + private final TransactionStatus result; + private final Collection errors; + + public DummyRpcResult() { + isSuccessful = false; + result = null; + errors = null; + } + + private DummyRpcResult(Builder builder) { + isSuccessful = builder.isSuccessful; + result = builder.result; + errors = builder.errors; + } + + public static Builder builder() { + return new DummyRpcResult.Builder(); + } + + @Override + public boolean isSuccessful() { + return isSuccessful; + } + + @Override + public TransactionStatus getResult() { + return result; + } + + @Override + public Collection getErrors() { + return errors; + } + + public static class Builder { + private boolean isSuccessful; + private TransactionStatus result; + private Collection errors; + + public Builder isSuccessful(boolean isSuccessful) { + this.isSuccessful = isSuccessful; + return this; + } + + public Builder result(TransactionStatus result) { + this.result = result; + return this; + } + + public Builder errors(Collection errors) { + this.errors = errors; + return this; + } + + public RpcResult build() { + return new DummyRpcResult(this); + } + + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNode.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java similarity index 71% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNode.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java index dbbb4a6996..2e8b071519 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNode.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromJsonToCompositeNodeTest.java @@ -25,20 +25,53 @@ import org.opendaylight.yangtools.yang.model.api.*; import com.google.gson.JsonSyntaxException; -public class FromJsonToCompositeNode { +public class FromJsonToCompositeNodeTest { - private static Logger LOG = LoggerFactory.getLogger(FromJsonToCompositeNode.class); + private static final Logger LOG = LoggerFactory.getLogger(FromJsonToCompositeNodeTest.class); @Test public void simpleListTest() { simpleTest("/json-to-composite-node/simple-list.json", "/json-to-composite-node/simple-list-yang", "lst", - "simple:data:types"); + "simple:list:yang1", "simple-list-yang1"); } @Test public void simpleContainerTest() { simpleTest("/json-to-composite-node/simple-container.json", "/json-to-composite-node/simple-container-yang", - "cont", "simple:data:types"); + "cont", "simple:container:yang", "simple-container-yang"); + } + + /** + * test if for every leaf list item is simple node instance created + */ + @Test + public void multipleItemsInLeafList() { + CompositeNode compositeNode = compositeContainerFromJson( + "/json-to-composite-node/multiple-leaflist-items.json", true); + assertNotNull(compositeNode); + assertEquals(3, compositeNode.getChildren().size()); + + boolean lflst1_1 = false; + boolean lflst1_2 = false; + boolean lflst1_3 = false; + + for (Node node : compositeNode.getChildren()) { + assertEquals("lflst1", node.getNodeType().getLocalName()); + assertTrue(node instanceof SimpleNode); + SimpleNode simpleNode = (SimpleNode) node; + if (simpleNode.getValue().equals("45")) { + lflst1_1 = true; + } else if (simpleNode.getValue().equals("55")) { + lflst1_2 = true; + } else if (simpleNode.getValue().equals("66")) { + lflst1_3 = true; + } + } + + assertTrue(lflst1_1); + assertTrue(lflst1_2); + assertTrue(lflst1_3); + } /** @@ -56,6 +89,21 @@ public class FromJsonToCompositeNode { verityMultipleItemsInList(compositeNode); } + @Test + public void nullArrayToSimpleNodeWithNullValueTest() { + CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/array-with-null.json", true); + assertNotNull(compositeNode); + assertEquals("cont", compositeNode.getNodeType().getLocalName()); + + assertNotNull(compositeNode.getChildren()); + assertEquals(1, compositeNode.getChildren().size()); + Node lfNode = compositeNode.getChildren().iterator().next(); + + assertTrue(lfNode instanceof SimpleNode); + assertEquals(null, ((SimpleNode) lfNode).getValue()); + + } + @Test public void incorrectTopLevelElementsTest() { Throwable cause1 = null; @@ -124,13 +172,57 @@ public class FromJsonToCompositeNode { } - private void simpleTest(String jsonPath, String yangPath, String topLevelElementName, String namespace) { + /** + * Tests whether namespace stay unchanged if concrete values are + * present in composite or simple node and if the method for update is + * called. + * + */ + @Test + public void notSupplyNamespaceIfAlreadySupplied() { + + CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/simple-list.json"); + assertNotNull(compositeNode); + + DataSchemaNode dataSchemaNode1 = null; + DataSchemaNode dataSchemaNode2 = null; + try { + dataSchemaNode1 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang", + "simple-list-yang1"); + dataSchemaNode2 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang", + "simple-list-yang2"); + } catch (FileNotFoundException e) { + LOG.error(e.getMessage()); + assertTrue(false); + } + assertNotNull(dataSchemaNode1); + assertNotNull(dataSchemaNode2); + + // supplement namespaces according to first data schema - + // "simple:data:types1" + TestUtils.supplementNamespace(dataSchemaNode1, compositeNode); + + assertTrue(compositeNode instanceof CompositeNodeWrapper); + CompositeNode compNode = ((CompositeNodeWrapper) compositeNode).unwrap(null); + + assertEquals("lst", compNode.getNodeType().getLocalName()); + verifyCompositeNode(compNode, "simple:list:yang1"); + + // dataSchemaNode2 should't be taken into account, because compNode + // isn't CompositeNodeWrapper + TestUtils.supplementNamespace(dataSchemaNode2, compNode); + verifyCompositeNode(compNode, "simple:list:yang1"); + + } + + private void simpleTest(String jsonPath, String yangPath, String topLevelElementName, String namespace, + String moduleName) { CompositeNode compositeNode = compositeContainerFromJson(jsonPath); assertNotNull(compositeNode); DataSchemaNode dataSchemaNode = null; try { - dataSchemaNode = TestUtils.obtainSchemaFromYang(yangPath); + dataSchemaNode = TestUtils.obtainSchemaFromYang(yangPath, moduleName); } catch (FileNotFoundException e) { LOG.error(e.getMessage()); assertTrue(false); @@ -234,7 +326,7 @@ public class FromJsonToCompositeNode { throws WebApplicationException { JsonToCompositeNodeProvider jsonToCompositeNodeProvider = JsonToCompositeNodeProvider.INSTANCE; - InputStream jsonStream = FromJsonToCompositeNode.class.getResourceAsStream(jsonPath); + InputStream jsonStream = FromJsonToCompositeNodeTest.class.getResourceAsStream(jsonPath); try { CompositeNode compositeNode = jsonToCompositeNodeProvider .readFrom(null, null, null, null, null, jsonStream); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNode.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java similarity index 87% rename from opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNode.java rename to opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java index 093cac57d0..ef122dd8d7 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNode.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/FromXmlToCompositeNodeTest.java @@ -11,13 +11,13 @@ import javax.ws.rs.WebApplicationException; import org.junit.*; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; -import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.*; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.slf4j.*; -public class FromXmlToCompositeNode { - private static Logger LOG = LoggerFactory.getLogger(FromXmlToCompositeNode.class); +public class FromXmlToCompositeNodeTest { + private static final Logger LOG = LoggerFactory.getLogger(FromXmlToCompositeNodeTest.class); /** * top level element represents container. second level element is list with @@ -41,9 +41,36 @@ public class FromXmlToCompositeNode { String nameSpace = "data:container:yang"; assertEquals(nameSpace, compNode.getNodeType().getNamespace().toString()); + verifyNullAndEmptyStringSingleNode(compNode, nameSpace); verifyCommonPartAOfXml(compNode, "", nameSpace); } + private void verifyNullAndEmptyStringSingleNode(CompositeNode compNode, String nameSpace) { + assertEquals("cont", compNode.getNodeType().getLocalName()); + + SimpleNode lf2 = null; + SimpleNode lf3 = null; + int found = 0; + for (Node child : compNode.getChildren()) { + if (found == 0x3) + break; + if (child instanceof SimpleNode) { + SimpleNode childSimple = (SimpleNode) child; + if (childSimple.getNodeType().getLocalName().equals("lf3")) { + lf3 = childSimple; + found = found | (1 << 0); + } else if (childSimple.getNodeType().getLocalName().equals("lf2")) { + lf2 = childSimple; + found = found | (1 << 1); + } + } + assertEquals(nameSpace, child.getNodeType().getNamespace().toString()); + } + + assertEquals("", lf2.getValue()); + assertEquals(null, lf3.getValue()); + } + @Test public void testXmlDataList() { CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-list.xml", false); @@ -230,7 +257,7 @@ public class FromXmlToCompositeNode { private CompositeNode compositeContainerFromXml(String xmlPath, boolean dummyNamespaces) { XmlToCompositeNodeProvider xmlToCompositeNodeProvider = XmlToCompositeNodeProvider.INSTANCE; try { - InputStream xmlStream = FromXmlToCompositeNode.class.getResourceAsStream(xmlPath); + InputStream xmlStream = FromXmlToCompositeNodeTest.class.getResourceAsStream(xmlPath); CompositeNode compositeNode = xmlToCompositeNodeProvider.readFrom(null, null, null, null, null, xmlStream); if (dummyNamespaces) { try { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index 3d06e4a759..c43de5d9e8 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -10,16 +10,22 @@ import java.io.*; import java.net.*; import java.sql.Date; import java.util.*; +import java.util.concurrent.Future; import javax.ws.rs.WebApplicationException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLStreamException; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.restconf.impl.*; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.*; import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder; import org.opendaylight.yangtools.yang.model.api.*; @@ -27,6 +33,9 @@ import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.slf4j.*; import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import com.google.common.base.Preconditions; final class TestUtils { @@ -90,8 +99,20 @@ final class TestUtils { } return (CompositeNode) dataTree; } + + public static Document loadDocumentFrom(InputStream inputStream) { + try { + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + return docBuilder.parse(inputStream); + } catch (SAXException | IOException | ParserConfigurationException e) { + logger.error("Error during loading Document from XML", e); + return null; + } + } public static String getDocumentInPrintableForm(Document doc) { + Preconditions.checkNotNull(doc); try { ByteArrayOutputStream out = new ByteArrayOutputStream(); TransformerFactory tf = TransformerFactory.newInstance(); @@ -272,9 +293,10 @@ final class TestUtils { ControllerContext controllerContext = mock(ControllerContext.class); BrokerFacade broker = mock(BrokerFacade.class); + RpcResult rpcResult = DummyRpcResult.builder().result(TransactionStatus.COMMITED).build(); + Future> future = DummyFuture.builder().rpcResult(rpcResult).build(); when(controllerContext.toInstanceIdentifier(any(String.class))).thenReturn(instIdAndSchema); - when(broker.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn( - new DummyFuture()); + when(broker.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(future); restconf.setControllerContext(controllerContext); restconf.setBroker(broker); @@ -298,15 +320,15 @@ final class TestUtils { if (modules.size() < 1) { return null; } - - Module moduleRes = null; + + Module moduleRes = null; if (modules.size() > 1) { if (moduleName == null) { return null; } else { - for (Module module: modules) { + for (Module module : modules) { if (module.getName().equals(moduleName)) { - moduleRes = module; + moduleRes = module; } } if (moduleRes == null) { @@ -316,7 +338,7 @@ final class TestUtils { } else { moduleRes = modules.iterator().next(); } - + if (moduleRes.getChildNodes() == null) { return null; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java index f88a335f18..69de9f86c1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonBasicDataTypesTest.java @@ -18,10 +18,6 @@ public class ToJsonBasicDataTypesTest { @Test public void simpleYangDataTest() { String jsonOutput; - // jsonOutput = - // TestUtils.readJsonFromFile("/yang-to-json-conversion/simple-yang-types/xml/awaited_output.json", - // false); - jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson( TestUtils.loadCompositeNode("/yang-to-json-conversion/simple-data-types/xml/data.xml"), "/yang-to-json-conversion/simple-data-types", "/yang-to-json-conversion/simple-data-types/xml"); @@ -73,7 +69,7 @@ public class ToJsonBasicDataTypesTest { // boolean lfref1Checked = false; boolean lfemptyChecked = false; boolean lfstr1Checked = false; - + while (jReader.hasNext()) { String keyName = jReader.nextName(); JsonToken peek = null; @@ -148,10 +144,8 @@ public class ToJsonBasicDataTypesTest { jReader.nextNull(); jReader.endArray(); lfemptyChecked = true; - // TODO: test will be implemented when functionality will be - // implemented - } else if (keyName.equals("lflstunion")) { - jReader.skipValue(); + } else if (keyName.startsWith("lfunion")) { + checkLfUnion(jReader, keyName, peek); } else { assertTrue("Key " + keyName + " doesn't exists in yang file.", false); } @@ -180,4 +174,44 @@ public class ToJsonBasicDataTypesTest { jReader.endObject(); } + + private void checkLfUnion(JsonReader jReader, String keyName, JsonToken peek) throws IOException { + if (keyName.equals("lfunion1")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion2")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion3")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextInt(); + } else if (keyName.equals("lfunion4")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + jReader.nextBoolean(); + } else if (keyName.equals("lfunion5")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion6")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion7")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion8")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion9")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion10")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion11")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); + jReader.nextString(); + } else if (keyName.equals("lfunion12")) { + assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); + jReader.nextBoolean(); + } + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java index baf226712f..015dfc8ad9 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlProvidersTest.java @@ -1,22 +1,19 @@ package org.opendaylight.controller.sal.restconf.impl.test; -import static org.mockito.Mockito.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.FileNotFoundException; -import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; -import java.util.Collection; import java.util.List; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -24,11 +21,7 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.glassfish.jersey.test.TestProperties; @@ -43,15 +36,11 @@ import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.MediaTypes; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; import com.google.common.base.Charsets; @@ -60,15 +49,11 @@ public class XmlProvidersTest extends JerseyTest { private static ControllerContext controllerContext; private static BrokerFacade brokerFacade; private static RestconfImpl restconfImpl; + private static final MediaType MEDIA_TYPE = new MediaType("application", "vnd.yang.api+xml"); @BeforeClass - public static void init() { - Set allModules = null; - try { - allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath()); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } + public static void init() throws FileNotFoundException { + Set allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath()); SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules); controllerContext = ControllerContext.getInstance(); controllerContext.setSchemas(schemaContext); @@ -87,96 +72,110 @@ public class XmlProvidersTest extends JerseyTest { } @Test - public void testStructuredDataToXmlProvider() throws FileNotFoundException { - URI uri = null; - try { - uri = new URI("/datastore/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString()); - } catch (UnsupportedEncodingException | URISyntaxException e) { - e.printStackTrace(); - } + public void testStructuredDataToXmlProvider() throws FileNotFoundException, UnsupportedEncodingException { + String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream); when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode); - Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).get(); + Response response = target(uri).request(MEDIA_TYPE).get(); assertEquals(200, response.getStatus()); } @Test - public void testXmlToCompositeNodeProvider() throws ParserConfigurationException, SAXException, IOException { - URI uri = null; - try { - uri = new URI("/config/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString()); - } catch (UnsupportedEncodingException | URISyntaxException e) { - e.printStackTrace(); - } - InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); - final CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream); - when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(new Future>() { - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - @Override - public boolean isCancelled() { - return false; - } - @Override - public boolean isDone() { - return false; - } - @Override - public RpcResult get() throws InterruptedException, ExecutionException { - return null; - } - @Override - public RpcResult get(long timeout, TimeUnit unit) throws InterruptedException, - ExecutionException, TimeoutException { - return null; - } - }); + public void testBadFormatXmlToCompositeNodeProvider() throws UnsupportedEncodingException, URISyntaxException { + String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/eth0"); - DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); - xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); - Document doc = docBuilder.parse(xmlStream); + Response response = target(uri).request(MediaTypes.API + RestconfService.XML).post( + Entity.entity("", MEDIA_TYPE)); + assertEquals(400, response.getStatus()); - Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).post(Entity.entity(TestUtils.getDocumentInPrintableForm(doc), new MediaType("application","vnd.yang.api+xml"))); - assertEquals(204, response.getStatus()); + response = target(uri).request(MediaTypes.API + RestconfService.XML).post( + Entity.entity("", MEDIA_TYPE)); + assertEquals(400, response.getStatus()); } @Test - public void testXmlToCompositeNodeProviderExceptions() { - URI uri = null; - try { - uri = new URI("/operations/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString()); - } catch (UnsupportedEncodingException | URISyntaxException e) { - e.printStackTrace(); - } + public void testXmlToCompositeNode404NotFound() throws UnsupportedEncodingException, URISyntaxException { + String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); - Response response = target(uri.toASCIIString()).request(MediaTypes.API + RestconfService.XML).post( - Entity.entity("", new MediaType("application", "vnd.yang.api+xml"))); - assertEquals(400, response.getStatus()); + when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null); - response = target(uri.toASCIIString()).request(MediaTypes.API + RestconfService.XML).post( - Entity.entity("", new MediaType("application", "vnd.yang.api+xml"))); - assertEquals(400, response.getStatus()); + Response response = target(uri).request(MediaTypes.API+RestconfService.XML).get(); + assertEquals(404, response.getStatus()); } @Test - public void testXmlToCompositeNode404NotFound() { - URI uri = null; - try { - uri = new URI("/datastore/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString()); - } catch (UnsupportedEncodingException | URISyntaxException e) { - e.printStackTrace(); - } + public void testXmlToCompositeNode400() throws UnsupportedEncodingException, URISyntaxException { + String uri = createUri("/datastore/", "simple-nodes:user/name"); when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null); - Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).get(); - assertEquals(404, response.getStatus()); + Response response = target(uri).request(MediaTypes.API+RestconfService.XML).get(); + assertEquals(400, response.getStatus()); + } + + @Test + public void testRpcResultCommitedToStatusCodes() throws UnsupportedEncodingException { + InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); + String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream)); + Entity entity = Entity.entity(xml, MEDIA_TYPE); + RpcResult rpcResult = DummyRpcResult.builder().result(TransactionStatus.COMMITED).build(); + Future> dummyFuture = DummyFuture.builder().rpcResult(rpcResult).build(); + when(brokerFacade.commitOperationalDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + + String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0"); + Response response = target(uri).request(MEDIA_TYPE).put(entity); + assertEquals(200, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(204, response.getStatus()); + + uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0"); + response = target(uri).request(MEDIA_TYPE).put(entity); + assertEquals(200, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(204, response.getStatus()); + + uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); + response = target(uri).request(MEDIA_TYPE).put(entity); + assertEquals(200, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(204, response.getStatus()); + } + + @Test + public void testRpcResultOtherToStatusCodes() throws UnsupportedEncodingException { + InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml"); + String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream)); + Entity entity = Entity.entity(xml, MEDIA_TYPE); + RpcResult rpcResult = DummyRpcResult.builder().result(TransactionStatus.FAILED).build(); + Future> dummyFuture = DummyFuture.builder().rpcResult(rpcResult).build(); + when(brokerFacade.commitOperationalDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + when(brokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + + String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0"); + Response response = target(uri).request(MEDIA_TYPE).put(entity); + assertEquals(500, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(500, response.getStatus()); + + uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0"); + response = target(uri).request(MEDIA_TYPE).put(entity); + assertEquals(500, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(500, response.getStatus()); + + uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0"); + response = target(uri).request(MEDIA_TYPE).put(entity); + assertEquals(500, response.getStatus()); + response = target(uri).request(MEDIA_TYPE).post(entity); + assertEquals(500, response.getStatus()); + } + + private String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException { + return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString(); } @Override diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json new file mode 100644 index 0000000000..a19d9485f6 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/array-with-null.json @@ -0,0 +1,5 @@ +{ + "cont": { + "lf":[null] + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json new file mode 100644 index 0000000000..b61a8a8f2e --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/multiple-leaflist-items.json @@ -0,0 +1,5 @@ +{ + "cont": { + "lflst1":[45,55,66] + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang index ddd67f7f80..493101ced1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-container-yang/simple-container.yang @@ -1,5 +1,5 @@ -module simple-data-types { - namespace "simple:data:types"; +module simple-container-yang { + namespace "simple:container:yang"; prefix "smpdtp"; revision 2013-11-12 { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang similarity index 68% rename from opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list.yang rename to opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang index af8edfaf7f..0ce8ea428c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list1.yang @@ -1,7 +1,7 @@ -module simple-data-types { - namespace "simple:data:types"; +module simple-list-yang1 { + namespace "simple:list:yang1"; - prefix "smpdtp"; + prefix "smplstyg"; revision 2013-11-12 { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang new file mode 100644 index 0000000000..0872a4754d --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-composite-node/simple-list-yang/simple-list2.yang @@ -0,0 +1,20 @@ +module simple-list-yang2 { + namespace "simple:list:yang2"; + + prefix "smplstyg"; + revision 2013-11-12 { + } + + list lst { + container cont1 { + } + list lst1 { + } + leaf-list lflst1 { + type string; + } + leaf lf1 { + type string; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang index 7c17bf9fdf..b038eb193c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container-yang/data-container.yang @@ -2,13 +2,22 @@ module data-container-yang { namespace "data:container:yang"; prefix "dtconyg"; - revision 2013-11-19 { + revision 2013-11-19 { } container cont { leaf lf1 { type string; } + + leaf lf2 { + type string; + } + + leaf lf3 { + type empty; + } + leaf-list lflst1 { type string; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml index 0c60fbcff3..ce97dd1715 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-composite-node/data-container.xml @@ -1,5 +1,7 @@ str0 + + 121 131 str1 diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang index 010d3b1c2b..759b3ecf71 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/simple-data-types.yang @@ -5,6 +5,45 @@ module simple-data-types { revision 2013-11-12 { } + typedef tpdfempty { + type empty; + } + + typedef tpdfbit { + type bits { + bit b1; + bit b2; + bit b3; + } + } + + typedef tpdfun4 { + type boolean; + } + + typedef tpdfun3 { + type union { + type tpdfbit; + type tpdfempty; + } + } + + typedef tpdfun2 { + type union { + type tpdfun3; + type tpdfun4; + } + } + + typedef tpdfun1 { + type union { + type uint8; + type decimal64 { + fraction-digits 2; + } + } + } + container cont { leaf lfnint8Min { type int8; @@ -125,12 +164,87 @@ module simple-data-types { type empty; } - leaf-list lflstunion { + leaf lfunion1 { type union { type uint16; type string; } } + leaf lfunion2 { + type union { + type decimal64 { + fraction-digits 2; + } + type string; + } + } + + leaf lfunion3 { + type union { + type empty; + type string; + } + } + + leaf lfunion4 { + type union { + type boolean; + type string; + } + } + + leaf lfunion5 { + type union { + type uint16; + type string; + } + } + + leaf lfunion6 { + type union { + type uint16; + type empty; + } + } + + leaf lfunion7 { + type tpdfun3; + } + + leaf lfunion8 { + type union { + type uint16; + type string; + } + } + + leaf lfunion9 { + type union { + type uint16; + type boolean; + } + } + + leaf lfunion10 { + type union { + type bits { + bit bt1; + bit bt2; + } + type boolean; + } + } + + leaf lfunion11 { + type union { + type tpdfun1; + type tpdfun2; + } + } + + leaf lfunion12 { + type tpdfun2; + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml index df00ca917e..0d31e9037a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/simple-data-types/xml/data.xml @@ -24,8 +24,16 @@ bit3 AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%%-#^ - 324 - 33.3 - lfunion - true + 324 + 33.3 + 55 + true + true + false + + + + bt1 + 33 + false \ No newline at end of file diff --git a/opendaylight/md-sal/samples/pom.xml b/opendaylight/md-sal/samples/pom.xml index 04e0a32ffb..6b87a22418 100644 --- a/opendaylight/md-sal/samples/pom.xml +++ b/opendaylight/md-sal/samples/pom.xml @@ -27,7 +27,7 @@ false - toaster-it + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java index c207db0478..bbbb5c8566 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java @@ -232,7 +232,7 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(); groupFeatures.setActions(notification.getActions()); groupFeatures.setCapabilities(notification.getCapabilities()); - groupFeatures.setGroupType(notification.getGroupType()); + groupFeatures.setTypes(notification.getTypes()); groupFeatures.setMaxGroups(notification.getMaxGroups()); cache.get(notification.getId()).setGroupFeatures(groupFeatures.build()); diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java index 97d2a6d02a..6ec4c2ce01 100644 --- a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java +++ b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java @@ -19,10 +19,12 @@ public interface RoutingTable { * * @param routeId route identifier * @param route network address + * @throws RoutingTableException for any logical exception + * @throws SystemException */ - public void addRoute(I routeId, R route) throws SystemException, RoutingTableException; + public void addRoute(I routeId, R route) throws RoutingTableException,SystemException; - /** + /** * Adds a network address for the route. If the route already exists, * it throws DuplicateRouteException. * This method would be used when registering a global service. @@ -31,6 +33,7 @@ public interface RoutingTable { * @param routeId route identifier * @param route network address * @throws DuplicateRouteException + * @throws RoutingTableException */ public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException; @@ -50,8 +53,10 @@ public interface RoutingTable { * Remove the route. * This method would be used when registering a global service. * @param routeId + * @throws RoutingTableException + * @throws SystemException */ - public void removeGlobalRoute(I routeId); + public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException; /** * Returns a set of network addresses associated with this route @@ -69,6 +74,13 @@ public interface RoutingTable { */ public R getARoute(I routeId); + /** + * + * This will be removed after listeners + * have made change on their end to use whiteboard pattern + * @deprecated + */ + public void registerRouteChangeListener(RouteChangeListener listener); public class DuplicateRouteException extends RoutingTableException { diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java index 45414437cc..6e2d280a89 100644 --- a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java +++ b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl; import org.apache.felix.dm.Component; import org.opendaylight.controller.clustering.services.ICacheUpdateAware; import org.opendaylight.controller.clustering.services.IClusterGlobalServices; +import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; import org.slf4j.Logger; @@ -72,6 +73,15 @@ public class Activator extends ComponentActivatorAbstractBase { c.setInterface(new String[] { RoutingTable.class.getName(),ICacheUpdateAware.class.getName() }, props); logger.debug("configureGlobalInstance adding dependency:", IClusterGlobalServices.class); + + // RouteChangeListener services will be none or many so the + // dependency is optional + c.add(createServiceDependency() + .setService(RouteChangeListener.class) + .setCallbacks("setRouteChangeListener", "unsetRouteChangeListener") + .setRequired(false)); + + //dependency is required as it provides us the caching support c.add(createServiceDependency().setService( IClusterGlobalServices.class).setCallbacks( "setClusterGlobalServices", diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java index 558c8a80d3..4e1dfb0058 100644 --- a/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java +++ b/opendaylight/md-sal/zeromq-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java @@ -10,12 +10,16 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl; import com.google.common.base.Preconditions; import org.apache.felix.dm.Component; -import org.opendaylight.controller.clustering.services.*; +import org.opendaylight.controller.clustering.services.CacheConfigException; +import org.opendaylight.controller.clustering.services.CacheExistException; +import org.opendaylight.controller.clustering.services.CacheListenerAddException; +import org.opendaylight.controller.clustering.services.ICacheUpdateAware; +import org.opendaylight.controller.clustering.services.IClusterGlobalServices; +import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; -import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,243 +27,298 @@ import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; -import java.util.*; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ConcurrentMap; /** * @author: syedbahm */ -public class RoutingTableImpl implements RoutingTable,ICacheUpdateAware { +public class RoutingTableImpl implements RoutingTable, ICacheUpdateAware { public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache"; - private Logger log = LoggerFactory - .getLogger(RoutingTableImpl.class); - - private IClusterGlobalServices clusterGlobalServices = null; - private RoutingTableImpl routingTableInstance = null; - private ConcurrentMap routingTableCache = null; - private List routeChangeListeners = new ArrayList(); - private ServiceRegistration cacheAwareRegistration = null; - - public RoutingTableImpl() { - } - - @Override - public void addRoute(I routeId, R route) throws RoutingTableException { - throw new UnsupportedOperationException(" Not implemented yet!"); - } - - @Override - public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); - Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); - try { - - Set existingRoute = null; - // ok does the global route is already registered ? - if ((existingRoute = getRoutes(routeId)) == null) { - - if(log.isDebugEnabled()){ - log.debug("addGlobalRoute: adding a new route with id"+ routeId + " and value = "+route); - } - // lets start a transaction - clusterGlobalServices.tbegin(); - Set routes = new HashSet(); - routes.add(route); - routingTableCache.put(routeId, routes); - clusterGlobalServices.tcommit(); - } else { - throw new DuplicateRouteException(" There is already existing route " + existingRoute); - } - - } catch (NotSupportedException e) { - throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e); - } catch (HeuristicRollbackException e) { - throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e); - } catch (RollbackException e) { - throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e); - } catch (HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to create route id=" + routeId + "with route" + route, e); - } catch (javax.transaction.SystemException e){ - throw new SystemException ( "System error occurred - while trying to create with value",e); + private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class); + + private IClusterGlobalServices clusterGlobalServices = null; + private RoutingTableImpl routingTableInstance = null; + private ConcurrentMap routingTableCache = null; + private Set routeChangeListeners = Collections + .synchronizedSet(new HashSet()); + + public RoutingTableImpl() { } - } + @Override + public void addRoute(I routeId, R route) throws RoutingTableException { + throw new UnsupportedOperationException(" Not implemented yet!"); + } - @Override - public void removeRoute(I routeId, R route) { - throw new UnsupportedOperationException("Not implemented yet!"); - } @Override - public void removeGlobalRoute(I routeId) { - routingTableCache.remove(routeId); + public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); + Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); + try { + + Set existingRoute = null; + // ok does the global route is already registered ? + if ((existingRoute = getRoutes(routeId)) == null) { + + if (log.isDebugEnabled()) { + log.debug("addGlobalRoute: adding a new route with id" + routeId + " and value = " + + route); + } + // lets start a transaction + clusterGlobalServices.tbegin(); + Set routes = new HashSet(); + routes.add(route); + routingTableCache.put(routeId, routes); + clusterGlobalServices.tcommit(); + } else { + throw new DuplicateRouteException(" There is already existing route " + existingRoute); + } + + } catch (NotSupportedException e) { + throw new RoutingTableException("Transaction error - while trying to create route id=" + + routeId + "with route" + route, e); + } catch (HeuristicRollbackException e) { + throw new RoutingTableException("Transaction error - while trying to create route id=" + + routeId + "with route" + route, e); + } catch (RollbackException e) { + throw new RoutingTableException("Transaction error - while trying to create route id=" + + routeId + "with route" + route, e); + } catch (HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to create route id=" + + routeId + "with route" + route, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to create with value", e); + } + } - @Override - public Set getRoutes(I routeId) { + @Override + public void removeRoute(I routeId, R route) { + throw new UnsupportedOperationException("Not implemented yet!"); + } - //Note: currently works for global routes only wherein there is just single route - Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!"); - return (Set) routingTableCache.get(routeId); - } + @Override + public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!"); + try { + if (log.isDebugEnabled()) { + log.debug("removeGlobalRoute: removing a new route with id" + routeId); + } + // lets start a transaction + clusterGlobalServices.tbegin(); + + routingTableCache.remove(routeId); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (HeuristicRollbackException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (RollbackException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); + } + } - @Override - public R getARoute(I routeId) { - throw new UnsupportedOperationException("Not implemented yet!"); - } + @Override + public Set getRoutes(I routeId) { - /** - * Registers listener for sending any change notification - * - * @param listener - */ - @Override - public void registerRouteChangeListener(RouteChangeListener listener) { - routeChangeListeners.add(listener); - } + // Note: currently works for global routes only wherein there is just single + // route + Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!"); + return (Set) routingTableCache.get(routeId); + } + @Override + public R getARoute(I routeId) { + throw new UnsupportedOperationException("Not implemented yet!"); + } /** - * Returning the list of route change listeners for Unit testing - * Note: the package scope is default - * @return List of registered RouteChangeListener listeners + * @deprecated doesn't do anything will be removed once listeners used + * whiteboard pattern Registers listener for sending any change + * notification + * @param listener */ - List getRegisteredRouteChangeListeners(){ - return routeChangeListeners; - } + @Override + public void registerRouteChangeListener(RouteChangeListener listener) { - public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { - this.clusterGlobalServices = clusterGlobalServices; - } + } - public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { - if(cacheAwareRegistration != null) { - cacheAwareRegistration.unregister(); + public void setRouteChangeListener(RouteChangeListener rcl) { + if(rcl != null){ + routeChangeListeners.add(rcl); + }else{ + log.warn("setRouteChangeListener called with null listener"); + } + } + + public void unSetRouteChangeListener(RouteChangeListener rcl) { + if(rcl != null){ + routeChangeListeners.remove(rcl); + }else{ + log.warn("unSetRouteChangeListener called with null listener"); + } } - this.clusterGlobalServices = null; - } /** - * Creates the Routing Table clustered global services cache - * @throws CacheExistException -- cluster global services exception when cache exist - * @throws CacheConfigException -- cluster global services exception during cache config - * @throws CacheListenerAddException -- cluster global services exception during adding of listener + * Returning the set of route change listeners for Unit testing Note: the + * package scope is default + * + * @return List of registered RouteChangeListener listeners */ + Set getRegisteredRouteChangeListeners() { + return routeChangeListeners; + } - void createRoutingTableCache() throws CacheExistException, CacheConfigException, CacheListenerAddException { - // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it - // should be caching? - - // let us check here if the cache already exists -- if so don't create - if (!clusterGlobalServices.existCache( - ROUTING_TABLE_GLOBAL_CACHE)) { + public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { + this.clusterGlobalServices = clusterGlobalServices; + } - if(log.isDebugEnabled()){ - log.debug("createRoutingTableCache: creating a new routing table cache "+ROUTING_TABLE_GLOBAL_CACHE ); - } - routingTableCache = clusterGlobalServices.createCache( - ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - } else { - if(log.isDebugEnabled()){ - log.debug("createRoutingTableCache: found existing routing table cache "+ROUTING_TABLE_GLOBAL_CACHE ); + public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { + if((clusterGlobalServices != null ) && (this.clusterGlobalServices.equals(clusterGlobalServices))){ + this.clusterGlobalServices = null; } - routingTableCache = clusterGlobalServices.getCache( - ROUTING_TABLE_GLOBAL_CACHE); } - } - - /** - * Function called by the dependency manager when all the required - * dependencies are satisfied - * - */ - void init(Component c) { - try { - - createRoutingTableCache(); - } catch (CacheExistException e) { - throw new IllegalStateException("could not construct routing table cache"); - } catch (CacheConfigException e) { - throw new IllegalStateException("could not construct routing table cache"); - } catch (CacheListenerAddException e) { - throw new IllegalStateException("could not construct routing table cache"); + /** + * Creates the Routing Table clustered global services cache + * + * @throws CacheExistException + * -- cluster global services exception when cache exist + * @throws CacheConfigException + * -- cluster global services exception during cache config + * @throws CacheListenerAddException + * -- cluster global services exception during adding of listener + */ + + void createRoutingTableCache() throws CacheExistException, CacheConfigException, + CacheListenerAddException { + // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it + // should be caching? + + // let us check here if the cache already exists -- if so don't create + if (!clusterGlobalServices.existCache(ROUTING_TABLE_GLOBAL_CACHE)) { + + if (log.isDebugEnabled()) { + log.debug("createRoutingTableCache: creating a new routing table cache " + + ROUTING_TABLE_GLOBAL_CACHE); + } + routingTableCache = clusterGlobalServices.createCache(ROUTING_TABLE_GLOBAL_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); + } else { + if (log.isDebugEnabled()) { + log.debug("createRoutingTableCache: found existing routing table cache " + + ROUTING_TABLE_GLOBAL_CACHE); + } + routingTableCache = clusterGlobalServices.getCache(ROUTING_TABLE_GLOBAL_CACHE); + } + } - } + /** + * Function called by the dependency manager when all the required + * dependencies are satisfied + * + */ + void init(Component c) { + try { + + createRoutingTableCache(); + } catch (CacheExistException e) { + throw new IllegalStateException("could not construct routing table cache"); + } catch (CacheConfigException e) { + throw new IllegalStateException("could not construct routing table cache"); + } catch (CacheListenerAddException e) { + throw new IllegalStateException("could not construct routing table cache"); + } + } /** - * Get routing table method is useful for unit testing - * It has package scope + * Get routing table method is useful for unit testing It has package + * scope */ - ConcurrentMap getRoutingTableCache(){ + ConcurrentMap getRoutingTableCache() { return this.routingTableCache; } + /** + * Invoked when a new entry is available in the cache, the key is only + * provided, the value will come as an entryUpdate invocation + * + * @param key + * Key for the entry just created + * @param cacheName + * name of the cache for which update has been received + * @param originLocal + * true if the event is generated from this node + */ + @Override + public void entryCreated(I key, String cacheName, boolean originLocal) { + // TBD: do we require this. + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryCreated routeId = " + key + " cacheName=" + cacheName); + } + } - /** - * Invoked when a new entry is available in the cache, the key is - * only provided, the value will come as an entryUpdate invocation - * - * @param key Key for the entry just created - * @param cacheName name of the cache for which update has been - * received - * @param originLocal true if the event is generated from this - * node - */ - @Override - public void entryCreated(I key, String cacheName, boolean originLocal) { - //TBD: do we require this. - if(log.isDebugEnabled()){ - log.debug("RoutingTableUpdates: entryCreated routeId = "+key - + " cacheName="+cacheName - ); - } - } - - /** - * Called anytime a given entry is updated - * - * @param key Key for the entry modified - * @param new_value the new value the key will have - * @param cacheName name of the cache for which update has been - * received - * @param originLocal true if the event is generated from this - * node - */ - @Override - public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) { - if(log.isDebugEnabled()){ - log.debug("RoutingTableUpdates: entryUpdated routeId = "+key - + ",value = "+ new_value - + " ,cacheName="+cacheName - ); - } - for(RouteChangeListener rcl:routeChangeListeners){ - rcl.onRouteUpdated(key, new_value); - } - } - - /** - * Called anytime a given key is removed from the - * ConcurrentHashMap we are listening to. - * - * @param key Key of the entry removed - * @param cacheName name of the cache for which update has been - * received - * @param originLocal true if the event is generated from this - * node - */ - @Override - public void entryDeleted(I key, String cacheName, boolean originLocal) { - if(log.isDebugEnabled()){ - log.debug("RoutingTableUpdates: entryUpdated routeId = "+key - + " local = "+ originLocal - + " cacheName="+cacheName - ); - } - for(RouteChangeListener rcl:routeChangeListeners){ - rcl.onRouteDeleted(key); - } - } - } \ No newline at end of file + /** + * Called anytime a given entry is updated + * + * @param key + * Key for the entry modified + * @param new_value + * the new value the key will have + * @param cacheName + * name of the cache for which update has been received + * @param originLocal + * true if the event is generated from this node + */ + @Override + public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) { + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + ",value = " + new_value + + " ,cacheName=" + cacheName + " originLocal="+originLocal); + } + if (!originLocal) { + for (RouteChangeListener rcl : routeChangeListeners) { + rcl.onRouteUpdated(key, new_value); + } + } + } + + /** + * Called anytime a given key is removed from the ConcurrentHashMap we are + * listening to. + * + * @param key + * Key of the entry removed + * @param cacheName + * name of the cache for which update has been received + * @param originLocal + * true if the event is generated from this node + */ + @Override + public void entryDeleted(I key, String cacheName, boolean originLocal) { + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + " local = " + originLocal + + " cacheName=" + cacheName + " originLocal="+originLocal); + } + if (!originLocal) { + for (RouteChangeListener rcl : routeChangeListeners) { + rcl.onRouteDeleted(key); + } + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java b/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java index 75cc6f5da8..2ef251d9a1 100644 --- a/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java +++ b/opendaylight/md-sal/zeromq-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java @@ -103,7 +103,12 @@ public class RoutingTableImplTest { Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0); rti.registerRouteChangeListener(new RouteChangeListenerImpl()); - Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1); + Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0); //old should not work + //what about the new approach - using whiteboard pattern + rti.setRouteChangeListener(new RouteChangeListenerImpl()); + + Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1); //should not work + } @Test diff --git a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java b/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java index 3b6d398511..a7929e82fc 100644 --- a/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java +++ b/opendaylight/md-sal/zeromq-routingtable/integrationtest/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/ZeroMQRoutingTableTestIT.java @@ -21,7 +21,6 @@ import java.io.Serializable; import java.net.URI; import java.util.Set; - import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.options; @@ -41,6 +40,7 @@ public class public static final String YANG = "org.opendaylight.yangtools"; public static final String CONTROLLER = "org.opendaylight.controller"; public static final String YANGTOOLS = "org.opendaylight.yangtools"; + RoutingIdentifierImpl rii = new RoutingIdentifierImpl(); // get the OSGI bundle context @Inject private BundleContext bc; @@ -171,9 +171,6 @@ public class mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // - mavenBundle(YANG, "concepts").versionAsInProject(), - mavenBundle(YANG, "yang-binding").versionAsInProject(), // - mavenBundle(YANG, "yang-common").versionAsInProject(), // mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), mavenBundle("com.google.guava", "guava").versionAsInProject(), // mavenBundle("org.javassist", "javassist").versionAsInProject(), @@ -248,7 +245,7 @@ public class @Test public void testAddGlobalRoute () throws Exception{ - RoutingIdentifierImpl rii = new RoutingIdentifierImpl(); + routingTable.addGlobalRoute(rii,"172.27.12.1:5000"); Set routes = routingTable.getRoutes(rii); @@ -261,6 +258,20 @@ public class } + @Test + public void testDeleteGlobalRoute () throws Exception{ + + routingTable.removeGlobalRoute(rii); + + Set routes = routingTable.getRoutes(rii); + + Assert.assertNull(routes); + + + } + + + class RoutingIdentifierImpl implements RpcRouter.RouteIdentifier,Serializable { private final URI namespace = URI.create("http://cisco.com/example"); @@ -281,6 +292,28 @@ public class public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() { return InstanceIdentifier.of(instance); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RoutingIdentifierImpl that = (RoutingIdentifierImpl) o; + + if (QNAME != null ? !QNAME.equals(that.QNAME) : that.QNAME != null) return false; + if (instance != null ? !instance.equals(that.instance) : that.instance != null) return false; + if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = namespace != null ? namespace.hashCode() : 0; + result = 31 * result + (QNAME != null ? QNAME.hashCode() : 0); + result = 31 * result + (instance != null ? instance.hashCode() : 0); + return result; + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java index bdb9391e2b..59dc11f0b8 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.java @@ -15,9 +15,12 @@ import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import java.util.List; +import java.util.Map; public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy { + private static final Object PREFIX_SEPARATOR = ":"; + public ObjectNameAttributeReadingStrategy(DependencyAttribute attributeIfc) { super(attributeIfc); } @@ -35,11 +38,28 @@ public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReading private ObjectNameAttributeMappingStrategy.MappedDependency resolve(XmlElement firstChild) { XmlElement typeElement = firstChild.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY); - String serviceName = typeElement.getTextContent(); + Map.Entry prefixNamespace = typeElement.findNamespaceOfTextContent(); + + String serviceName = checkPrefixAndExtractServiceName(typeElement, prefixNamespace); + XmlElement nameElement = firstChild.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY); String dependencyName = nameElement.getTextContent(); - return new ObjectNameAttributeMappingStrategy.MappedDependency(serviceName, dependencyName); + return new ObjectNameAttributeMappingStrategy.MappedDependency(prefixNamespace.getValue(), serviceName, + dependencyName); + } + + public static String checkPrefixAndExtractServiceName(XmlElement typeElement, Map.Entry prefixNamespace) { + String serviceName = typeElement.getTextContent(); + + Preconditions.checkState(prefixNamespace.equals("") == false, "Service %s value not prefixed with namespace", + XmlNetconfConstants.TYPE_KEY); + String prefix = prefixNamespace.getKey() + PREFIX_SEPARATOR; + Preconditions.checkState(serviceName.startsWith(prefix), + "Service %s not correctly prefixed, expected %s, but was %s", XmlNetconfConstants.TYPE_KEY, prefix, + serviceName); + serviceName = serviceName.substring(prefix.length()); + return serviceName; } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java index d63e61cea8..3e63b92884 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java @@ -74,8 +74,9 @@ public class ObjectMapper extends AttributeIfcSwitchStatement> caseDependencyAttribute( DependencyAttribute attributeIfc) { String serviceName = attributeIfc.getDependency().getSie().getQName().getLocalName(); + String namespace = attributeIfc.getDependency().getSie().getQName().getNamespace().toString(); return new ObjectNameAttributeMappingStrategy((SimpleType) attributeIfc.getOpenType(), dependencyTracker, - serviceName); + serviceName, namespace); } @Override diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java index 1febf02a2d..f4d88c7c8e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java @@ -21,11 +21,13 @@ public class ObjectNameAttributeMappingStrategy extends private final Services tracker; private final String serviceName; + private final String namespace; - public ObjectNameAttributeMappingStrategy(SimpleType openType, Services dependencyTracker, String serviceName) { + public ObjectNameAttributeMappingStrategy(SimpleType openType, Services dependencyTracker, String serviceName, String namespace) { super(openType); this.tracker = dependencyTracker; this.serviceName = serviceName; + this.namespace = namespace; } @Override @@ -40,17 +42,18 @@ public class ObjectNameAttributeMappingStrategy extends Util.checkType(value, ObjectName.class); ObjectName on = (ObjectName) value; - String refName = tracker.addServiceEntry(serviceName, on); + String refName = tracker.addServiceEntry(namespace, serviceName, on); - return Optional.of(new MappedDependency(serviceName, refName)); + return Optional.of(new MappedDependency(namespace, serviceName, refName)); } public static class MappedDependency { - private final String serviceName, refName; + private final String namespace, serviceName, refName; - public MappedDependency(String serviceName, String refName) { + public MappedDependency(String namespace, String serviceName, String refName) { this.serviceName = serviceName; this.refName = refName; + this.namespace = namespace; } public String getServiceName() { @@ -61,10 +64,15 @@ public class ObjectNameAttributeMappingStrategy extends return refName; } + public String getNamespace() { + return namespace; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer("MappedDependency{"); - sb.append("serviceName='").append(serviceName).append('\''); + sb.append("namespace='").append(namespace).append('\''); + sb.append(", serviceName='").append(serviceName).append('\''); sb.append(", refName='").append(refName).append('\''); sb.append('}'); return sb.toString(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java index 5469015a23..c6f306b360 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java @@ -39,8 +39,12 @@ public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResol Util.checkType(value, ObjectNameAttributeMappingStrategy.MappedDependency.class); ObjectNameAttributeMappingStrategy.MappedDependency mappedDep = (ObjectNameAttributeMappingStrategy.MappedDependency) value; - ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(mappedDep.getServiceName(), - mappedDep.getRefName()); + String serviceName = mappedDep.getServiceName(); + String refName = mappedDep.getRefName(); + String namespace = mappedDep.getNamespace(); + logger.trace("Getting service instance by service name {} : {} and ref name {}", namespace, serviceName, refName); + + ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName); ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName()); logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType()); return Optional.of(on); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectNameAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectNameAttributeWritingStrategy.java index b88b6722c8..8563b781e3 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectNameAttributeWritingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectNameAttributeWritingStrategy.java @@ -37,8 +37,11 @@ public class ObjectNameAttributeWritingStrategy implements AttributeWritingStrat String moduleName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getServiceName(); String refName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getRefName(); + String namespaceForType = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getNamespace(); - final Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY, moduleName); + Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlNetconfConstants.TYPE_KEY, XmlNetconfConstants.PREFIX, + moduleName); + XmlUtil.addPrefixedNamespaceAttr(typeElement, XmlNetconfConstants.PREFIX, namespaceForType); innerNode.appendChild(typeElement); final Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, refName); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java index 8c7621a24b..f96b3acf20 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java @@ -8,13 +8,6 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; @@ -22,23 +15,41 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.management.ObjectName; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import static com.google.common.base.Preconditions.checkState; import static java.lang.String.format; public class Config { + private final Logger logger = LoggerFactory.getLogger(Config.class); - private final Map> moduleConfigs; + private final Map> moduleConfigs; + private final Map moduleNamesToConfigs; public Config(Map> moduleConfigs) { this.moduleConfigs = moduleConfigs; + Map moduleNamesToConfigs = new HashMap<>(); + for (Entry> entry : moduleConfigs.entrySet()) { + moduleNamesToConfigs.putAll(entry.getValue()); + } + this.moduleNamesToConfigs = Collections.unmodifiableMap(moduleNamesToConfigs); } private Map>> getMappedInstances(Set instancesToMap, @@ -64,7 +75,7 @@ public class Config { // All found instances add to service tracker in advance // This way all instances will be serialized as all available // services when get-config is triggered - // (even if they are not used as services by other onstances) + // (even if they are not used as services by other instances) // = more user friendly addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices()); @@ -76,10 +87,10 @@ public class Config { } private void addServices(Services serviceTracker, Collection instances, - Collection providedServices) { + Multimap providedServices) { for (ObjectName instanceOn : instances) { - for (String serviceName : providedServices) { - serviceTracker.addServiceEntry(serviceName, instanceOn); + for (Entry serviceName : providedServices.entries()) { + serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn); } } } @@ -138,6 +149,7 @@ public class Config { return root; } + // TODO remove commented modules from output private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace, Entry> moduleMappingEntry) { Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY); @@ -152,18 +164,19 @@ public class Config { // TODO refactor, replace string representing namespace with namespace class // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved // class - public Map> fromXml(XmlElement xml) { + public Map> fromXml(XmlElement xml, Set instancesForFillingServiceRefMapping, + EditStrategyType defaultEditStrategyType) { Map> retVal = Maps.newHashMap(); List recognisedChildren = Lists.newArrayList(); - Services serviceTracker = fromXmlServices(xml, recognisedChildren); + Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping); List moduleElements = fromXmlModules(xml, recognisedChildren); xml.checkUnrecognisedElements(recognisedChildren); for (XmlElement moduleElement : moduleElements) { - resolveModule(retVal, serviceTracker, moduleElement); + resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType); } return retVal; @@ -184,7 +197,7 @@ public class Config { } private void resolveModule(Map> retVal, Services serviceTracker, - XmlElement moduleElement) { + XmlElement moduleElement, EditStrategyType defaultStrategy) { XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY); Entry prefixToNamespace = typeElement.findNamespaceOfTextContent(); String moduleNamespace = prefixToNamespace.getValue(); @@ -203,24 +216,40 @@ public class Config { } ModuleElementResolved moduleElementResolved = moduleMapping.fromXml(moduleElement, serviceTracker, - instanceName, moduleNamespace); + instanceName, moduleNamespace, defaultStrategy); innerMap.put(factoryName, moduleElementResolved); } - private Services fromXmlServices(XmlElement xml, List recognisedChildren) { + private Services fromXmlServices(XmlElement xml, List recognisedChildren, Set instancesForFillingServiceRefMapping) { Optional servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG); - Map> mappedServices; + Map>> mappedServices; if (servicesElement.isPresent()) { mappedServices = Services.fromXml(servicesElement.get()); recognisedChildren.add(servicesElement.get()); } else { mappedServices = new HashMap<>(); } + Services services = Services.resolveServices(mappedServices); + // merge with what candidate db contains by default - ref_ + + for(ObjectName existingON: instancesForFillingServiceRefMapping) { + logger.trace("Filling services from {}", existingON); + // get all its services + String factoryName = ObjectNameUtil.getFactoryName(existingON); + ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName); + + checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs); + // Set services = ; + for (Entry serviceName : moduleConfig.getProvidedServices().entries()) { + + services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON); + } + } - return Services.resolveServices(mappedServices); + return services; } private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java index d1ba0b0206..33858746cb 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java @@ -24,6 +24,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attrib import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.AttributeWritingStrategy; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.ObjectXmlWriter; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.slf4j.Logger; @@ -109,22 +110,25 @@ public final class InstanceConfig { depTracker).prepareResolving(yangToAttrConfig); for (Entry configDefEntry : mappedConfig.getConfiguration().entrySet()) { + AttributeConfigElement value = configDefEntry.getValue(); + String attributeName = configDefEntry.getKey(); try { - AttributeResolvingStrategy> attributeResolvingStrategy = resolvingStrategies - .get(configDefEntry.getKey()); + .get(attributeName); + logger.trace("Trying to set value {} of attribute {} with {}", value, attributeName, attributeResolvingStrategy); - configDefEntry.getValue().resolveValue(attributeResolvingStrategy, configDefEntry.getKey()); - configDefEntry.getValue().setJmxName( - yangToAttrConfig.get(configDefEntry.getKey()).getUpperCaseCammelCase()); + value.resolveValue(attributeResolvingStrategy, attributeName); + value.setJmxName( + yangToAttrConfig.get(attributeName).getUpperCaseCammelCase()); } catch (Exception e) { - throw new IllegalStateException("Unable to resolve value " + configDefEntry.getValue() - + " to attribute " + configDefEntry.getKey(), e); + throw new IllegalStateException("Unable to resolve value " + value + + " to attribute " + attributeName, e); } } } - public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace) { + public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace, + EditStrategyType defaultStrategy) { Map retVal = Maps.newHashMap(); Map strats = new ObjectXmlReader().prepareReading(yangToAttrConfig); @@ -149,7 +153,7 @@ public final class InstanceConfig { XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved( - retVal) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal); + retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy); resolveConfiguration(instanceConfigElementResolved, services); return instanceConfigElementResolved; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java index 6624fc182e..e4bd9212e9 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java @@ -25,20 +25,26 @@ public class InstanceConfigElementResolved { private final EditStrategyType editStrategy; private final Map configuration; - public InstanceConfigElementResolved(String strat, Map configuration) { - EditStrategyType valueOf = checkStrategy(strat); + public InstanceConfigElementResolved(String currentStrategy, Map configuration, EditStrategyType defaultStrategy) { + EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy); this.editStrategy = valueOf; this.configuration = configuration; } - EditStrategyType checkStrategy(String strat) { - EditStrategyType valueOf = EditStrategyType.valueOf(strat); - if (EditStrategyType.defaultStrategy().isEnforcing()) { + public InstanceConfigElementResolved(Map configuration, EditStrategyType defaultStrategy) { + editStrategy = defaultStrategy; + this.configuration = configuration; + } + + + EditStrategyType checkStrategy(String currentStrategy, EditStrategyType defaultStrategy) { + EditStrategyType valueOf = EditStrategyType.valueOf(currentStrategy); + if (defaultStrategy.isEnforcing()) { Preconditions .checkArgument( - valueOf == EditStrategyType.defaultStrategy(), + valueOf == defaultStrategy, "With " - + EditStrategyType.defaultStrategy() + + defaultStrategy + " as " + EditConfigXmlParser.DEFAULT_OPERATION_KEY + " operations on module elements are not permitted since the default option is restrictive"); @@ -46,10 +52,6 @@ public class InstanceConfigElementResolved { return valueOf; } - public InstanceConfigElementResolved(Map configuration) { - editStrategy = EditStrategyType.defaultStrategy(); - this.configuration = configuration; - } public EditConfigStrategy getEditStrategy() { return editStrategy.getFittingStrategy(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java index 3a0c54754b..2e2a26400f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java @@ -8,38 +8,48 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.opendaylight.yangtools.yang.common.QName; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.management.ObjectName; import java.util.Collection; -import java.util.Collections; public class ModuleConfig { private final String moduleName; private final InstanceConfig instanceConfig; - private final Collection providedServices; + private final Multimap providedServices; - public ModuleConfig(String moduleName, InstanceConfig mbeanMapping, Collection providedServices) { + public ModuleConfig(String moduleName, InstanceConfig mbeanMapping, Collection providedServices) { this.moduleName = moduleName; this.instanceConfig = mbeanMapping; - this.providedServices = providedServices; + this.providedServices = mapServices(providedServices); } - public ModuleConfig(String key, InstanceConfig instanceConfig) { - this(key, instanceConfig, Collections. emptyList()); + private Multimap mapServices(Collection providedServices) { + Multimap mapped = HashMultimap.create(); + + for (QName providedService : providedServices) { + String key = providedService.getNamespace().toString(); + mapped.put(key, providedService.getLocalName()); + } + + return mapped; } public InstanceConfig getMbeanMapping() { return instanceConfig; } - public Collection getProvidedServices() { + public Multimap getProvidedServices() { return providedServices; } @@ -68,16 +78,16 @@ public class ModuleConfig { private String getPrefix(String namespace) { // if(namespace.contains(":")==false) - return "prefix"; + return XmlNetconfConstants.PREFIX; // return namespace.substring(namespace.lastIndexOf(':') + 1, // namespace.length()); } public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName, - String moduleNamespace) { + String moduleNamespace, EditStrategyType defaultStrategy) { - InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace); + InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy); return new ModuleElementResolved(instanceName, ice); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java index 7e4b6c2c06..e4fa6f504b 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java @@ -8,13 +8,17 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -29,6 +33,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Services { + private static final Logger logger = LoggerFactory.getLogger(Services.class); private static final String PROVIDER_KEY = "provider"; private static final String NAME_KEY = "name"; @@ -38,23 +43,33 @@ public final class Services { private long suffix = 1; private final Map instanceToRef = Maps.newHashMap(); - private final Map> serviceNameToRefNameToInstance = Maps + private final Map>> namespaceToServiceNameToRefNameToInstance = Maps .newHashMap(); - public String addServiceEntry(String serviceName, ObjectName on) { + public String addServiceEntry(String namespace, String serviceName, ObjectName on) { String moduleName = on.getKeyProperty("moduleFactoryName"); String instanceName = on.getKeyProperty("instanceName"); - return addServiceEntry(serviceName, moduleName, instanceName); + String refName = addServiceEntry(namespace, serviceName, moduleName, instanceName); + logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}", + serviceName, refName, moduleName, instanceName); + return refName; } - public String addServiceEntry(String serviceName, String moduleName, String instanceName) { + @VisibleForTesting + public String addServiceEntry(String namespace, String serviceName, String moduleName, String instanceName) { ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName); serviceInstance.setServiceName(serviceName); String refName = instanceToRef.get(serviceInstance); + Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace); + if (serviceNameToRefNameToInstance == null) { + serviceNameToRefNameToInstance = Maps.newHashMap(); + namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance); + } + Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); if (refNameToInstance == null) { refNameToInstance = Maps.newHashMap(); @@ -93,7 +108,11 @@ public final class Services { return refNamesAsSet; } - public ServiceInstance getByServiceAndRefName(String serviceName, String refName) { + public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) { + Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace); + Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , " + + serviceNameToRefNameToInstance.keySet()); + Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , " + serviceNameToRefNameToInstance.keySet()); @@ -106,20 +125,28 @@ public final class Services { // TODO hide getMappedServices, call it explicitly in toXml - public Map> getMappedServices() { - Map> retVal = Maps.newHashMap(); + public Map>> getMappedServices() { + Map>> retVal = Maps.newHashMap(); + + for (String namespace : namespaceToServiceNameToRefNameToInstance.keySet()) { - for (String serviceName : serviceNameToRefNameToInstance.keySet()) { + Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance + .get(namespace); + Map> innerRetVal = Maps.newHashMap(); - Map innerRetVal = Maps.transformValues(serviceNameToRefNameToInstance.get(serviceName), - new Function() { - @Nullable - @Override - public String apply(@Nullable ServiceInstance serviceInstance) { - return serviceInstance.toString(); - } - }); - retVal.put(serviceName, innerRetVal); + for (String serviceName : serviceNameToRefNameToInstance.keySet()) { + + Map innerInnerRetVal = Maps.transformValues( + serviceNameToRefNameToInstance.get(serviceName), new Function() { + @Nullable + @Override + public String apply(@Nullable ServiceInstance serviceInstance) { + return serviceInstance.toString(); + } + }); + innerRetVal.put(serviceName, innerInnerRetVal); + } + retVal.put(namespace, innerRetVal); } return retVal; @@ -127,35 +154,45 @@ public final class Services { // TODO hide resolveServices, call it explicitly in fromXml - public static Services resolveServices(Map> mappedServices) { + public static Services resolveServices(Map>> mappedServices) { Services tracker = new Services(); - for (Entry> serviceEntry : mappedServices.entrySet()) { + for (Entry>> namespaceEntry : mappedServices.entrySet()) { + String namespace = namespaceEntry.getKey(); - String serviceName = serviceEntry.getKey(); - for (Entry refEntry : serviceEntry.getValue().entrySet()) { + for (Entry> serviceEntry : namespaceEntry.getValue().entrySet()) { - Map refNameToInstance = tracker.serviceNameToRefNameToInstance - .get(serviceName); - if (refNameToInstance == null) { - refNameToInstance = Maps.newHashMap(); - tracker.serviceNameToRefNameToInstance.put(serviceName, refNameToInstance); - } + String serviceName = serviceEntry.getKey(); + for (Entry refEntry : serviceEntry.getValue().entrySet()) { - String refName = refEntry.getKey(); - Preconditions.checkState(false == refNameToInstance.containsKey(refName), - "Duplicate reference name to service " + refName + " under service " + serviceName); - ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue()); - refNameToInstance.put(refName, serviceInstance); + Map> namespaceToServices = tracker.namespaceToServiceNameToRefNameToInstance.get(namespace); + if (namespaceToServices == null) { + namespaceToServices = Maps.newHashMap(); + tracker.namespaceToServiceNameToRefNameToInstance.put(namespace, namespaceToServices); + } + + Map refNameToInstance = namespaceToServices + .get(serviceName); + if (refNameToInstance == null) { + refNameToInstance = Maps.newHashMap(); + namespaceToServices.put(serviceName, refNameToInstance); + } - tracker.instanceToRef.put(serviceInstance, refEntry.getKey()); + String refName = refEntry.getKey(); + Preconditions.checkState(false == refNameToInstance.containsKey(refName), + "Duplicate reference name to service " + refName + " under service " + serviceName); + ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue()); + refNameToInstance.put(refName, serviceInstance); + + tracker.instanceToRef.put(serviceInstance, refEntry.getKey()); + } } } return tracker; } - public static Map> fromXml(XmlElement xml) { - Map> retVal = Maps.newHashMap(); + public static Map>> fromXml(XmlElement xml) { + Map>> retVal = Maps.newHashMap(); List services = xml.getChildElements(SERVICE_KEY); xml.checkUnrecognisedElements(services); @@ -163,10 +200,20 @@ public final class Services { for (XmlElement service : services) { XmlElement typeElement = service.getOnlyChildElement(TYPE_KEY); - String serviceName = typeElement.getTextContent(); + Entry prefixNamespace = typeElement.findNamespaceOfTextContent(); + + Preconditions.checkState(prefixNamespace.getKey()!=null && prefixNamespace.getKey().equals("") == false, "Type attribute was not prefixed"); + + Map> namespaceToServices = retVal.get(prefixNamespace.getValue()); + if(namespaceToServices == null) { + namespaceToServices = Maps.newHashMap(); + retVal.put(prefixNamespace.getValue(), namespaceToServices); + } + + String serviceName = ObjectNameAttributeReadingStrategy.checkPrefixAndExtractServiceName(typeElement, prefixNamespace); Map innerMap = Maps.newHashMap(); - retVal.put(serviceName, innerMap); + namespaceToServices.put(serviceName, innerMap); List instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY); service.checkUnrecognisedElements(instances, typeElement); @@ -197,29 +244,34 @@ public final class Services { } } - public Element toXml(Map> mappedServices, Document document) { + public Element toXml(Map>> mappedServices, Document document) { Element root = document.createElement(XmlNetconfConstants.SERVICES_KEY); XmlUtil.addNamespaceAttr(root, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG); - for (Entry> serviceEntry : mappedServices.entrySet()) { - Element serviceElement = document.createElement(SERVICE_KEY); - root.appendChild(serviceElement); + for (String namespace : mappedServices.keySet()) { + + for (Entry> serviceEntry : mappedServices.get(namespace).entrySet()) { + Element serviceElement = document.createElement(SERVICE_KEY); + root.appendChild(serviceElement); - Element typeElement = XmlUtil.createTextElement(document, TYPE_KEY, serviceEntry.getKey()); - serviceElement.appendChild(typeElement); + Element typeElement = XmlUtil.createPrefixedTextElement(document, TYPE_KEY, XmlNetconfConstants.PREFIX, + serviceEntry.getKey()); + XmlUtil.addPrefixedNamespaceAttr(typeElement, XmlNetconfConstants.PREFIX, namespace); + serviceElement.appendChild(typeElement); - for (Entry instanceEntry : serviceEntry.getValue().entrySet()) { - Element instanceElement = document.createElement(XmlNetconfConstants.INSTANCE_KEY); - serviceElement.appendChild(instanceElement); + for (Entry instanceEntry : serviceEntry.getValue().entrySet()) { + Element instanceElement = document.createElement(XmlNetconfConstants.INSTANCE_KEY); + serviceElement.appendChild(instanceElement); - Element nameElement = XmlUtil.createTextElement(document, NAME_KEY, instanceEntry.getKey()); - instanceElement.appendChild(nameElement); + Element nameElement = XmlUtil.createTextElement(document, NAME_KEY, instanceEntry.getKey()); + instanceElement.appendChild(nameElement); - Element providerElement = XmlUtil.createTextElement(document, PROVIDER_KEY, instanceEntry.getValue()); - instanceElement.appendChild(providerElement); + Element providerElement = XmlUtil.createTextElement(document, PROVIDER_KEY, instanceEntry.getValue()); + instanceElement.appendChild(providerElement); + } } - } + } return root; } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java index 556541ab22..ef286ac862 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/rpc/Rpcs.java @@ -24,8 +24,9 @@ public class Rpcs { public ModuleRpcs getRpcMapping(RuntimeRpcElementResolved id) { Map modules = mappedRpcs.get(id.getNamespace()); Preconditions.checkState(modules != null, "No modules found for namespace %s", id.getNamespace()); - ModuleRpcs rpcMapping = modules.get(id.getModuleName()); - Preconditions.checkState(modules != null, "No module %s found for namespace %s", id.getModuleName(), + String moduleName = id.getModuleName(); + ModuleRpcs rpcMapping = modules.get(moduleName); + Preconditions.checkState(rpcMapping != null, "No module %s found for namespace %s", moduleName, id.getNamespace()); return rpcMapping; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java index 9d348d0985..70b10d0019 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java @@ -12,7 +12,6 @@ import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Sets; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig; -import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -83,15 +82,14 @@ public class InstanceRuntime { })); } - public Element toXml(ObjectName rootOn, Set childRbeOns, Document document) { - return toXml(rootOn, childRbeOns, document, null, null); + public Element toXml(ObjectName rootOn, Set childRbeOns, Document document, Element parentElement, String namespace) { + return toXml(rootOn, childRbeOns, document, null, parentElement, namespace); } public Element toXml(ObjectName rootOn, Set childRbeOns, Document document, String instanceIndex, - String keyName) { - Element xml = document.createElement(keyName == null ? XmlNetconfConstants.DATA_KEY : keyName); + Element parentElement, String namespace) { // TODO namespace - xml = instanceMapping.toXml(rootOn, null, "namespace", document, xml); + Element xml = instanceMapping.toXml(rootOn, null, namespace, document, parentElement); if (instanceIndex != null) { xml.setAttribute(KEY_ATTRIBUTE_KEY, instanceIndex); @@ -106,8 +104,11 @@ public class InstanceRuntime { String runtimeInstanceIndex = objectName.getKeyProperty(childMappingEntry.getKey()); String elementName = jmxToYangChildRbeMapping.get(childMappingEntry.getKey()); - xml.appendChild(childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document, - runtimeInstanceIndex, elementName)); + + Element innerXml = document.createElement(elementName); + childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document, + runtimeInstanceIndex, innerXml, namespace); + xml.appendChild(innerXml); } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java index 07da65ed19..4dbfba119f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime; -import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -41,31 +40,30 @@ public class ModuleRuntime { throw new IllegalStateException("Root runtime bean not found among " + runtimeBeanOns); } - public Element toXml(String namespace, Multimap instances, Document document) { - Element root = document.createElement(XmlNetconfConstants.MODULE_KEY); - XmlUtil.addNamespaceAttr(root, namespace); + public Element toXml(String namespace, String instanceName, Collection runtimeBeanOns, Document document) { + Element moduleElement = document.createElement(XmlNetconfConstants.MODULE_KEY); - Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, moduleName); - root.appendChild(nameElement); + final String prefix = getPrefix(namespace); + Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlNetconfConstants.TYPE_KEY, prefix, + moduleName); + XmlUtil.addPrefixedNamespaceAttr(typeElement, prefix, namespace); + moduleElement.appendChild(typeElement); - for (String instanceName : instances.keySet()) { - Element instance = document.createElement(XmlNetconfConstants.INSTANCE_KEY); + Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName); + moduleElement.appendChild(nameElement); - Element innerNameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName); - instance.appendChild(innerNameElement); + ObjectName rootName = findRoot(runtimeBeanOns); - Collection runtimeBeanOns = instances.get(instanceName); - ObjectName rootName = findRoot(runtimeBeanOns); + Set childrenRuntimeBeans = Sets.newHashSet(runtimeBeanOns); + childrenRuntimeBeans.remove(rootName); - Set childrenRuntimeBeans = Sets.newHashSet(runtimeBeanOns); - childrenRuntimeBeans.remove(rootName); + instanceRuntime.toXml(rootName, childrenRuntimeBeans, document, moduleElement, namespace); - instance.appendChild(instanceRuntime.toXml(rootName, childrenRuntimeBeans, document)); - - root.appendChild(instance); - } + return moduleElement; + } - return root; + private String getPrefix(String namespace) { + return XmlNetconfConstants.PREFIX; } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java index da281269e6..8af1e0ee90 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java @@ -66,9 +66,12 @@ public class Runtime { if (instanceToRbe == null) continue; - ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName); - Element innerXml = moduleRuntime.toXml(localNamespace, instanceToRbe, document); - modulesElement.appendChild(innerXml); + for (String instanceName : instanceToRbe.keySet()) { + ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName); + Element innerXml = moduleRuntime.toXml(localNamespace, instanceName, instanceToRbe.get(instanceName), document); + modulesElement.appendChild(innerXml); + } + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java index be3b01db5d..101af48a89 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java @@ -27,6 +27,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; @@ -88,9 +89,9 @@ public class EditConfig extends AbstractConfigNetconfOperation { } private void executeTests(ConfigRegistryClient configRegistryClient, - EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException { + EditConfigExecution editConfigExecution) throws NetconfDocumentedException { try { - test(configRegistryClient, editConfigExecution.resolvedXmlElements); + test(configRegistryClient, editConfigExecution.getResolvedXmlElements(), editConfigExecution.getDefaultStrategy()); } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) { logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e); final Map errorInfo = new HashMap<>(); @@ -102,12 +103,12 @@ public class EditConfig extends AbstractConfigNetconfOperation { } private void test(ConfigRegistryClient configRegistryClient, - Map> resolvedModules) { + Map> resolvedModules, EditStrategyType editStrategyType) { ObjectName taON = transactionProvider.getTestTransaction(); try { // default strategy = replace wipes config - if (EditStrategyType.defaultStrategy() == EditStrategyType.replace) { + if (editStrategyType == EditStrategyType.replace) { transactionProvider.wipeTestTransaction(taON); } setOnTransaction(configRegistryClient, resolvedModules, taON); @@ -122,10 +123,10 @@ public class EditConfig extends AbstractConfigNetconfOperation { ObjectName taON = transactionProvider.getOrCreateTransaction(); // default strategy = replace wipes config - if (EditStrategyType.defaultStrategy() == EditStrategyType.replace) { + if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) { transactionProvider.wipeTransaction(); } - setOnTransaction(configRegistryClient, editConfigExecution.resolvedXmlElements, taON); + setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), taON); } private void setOnTransaction(ConfigRegistryClient configRegistryClient, @@ -147,14 +148,18 @@ public class EditConfig extends AbstractConfigNetconfOperation { } public static Config getConfigMapping(ConfigRegistryClient configRegistryClient, - Map> mBeanEntries) { + Map> mBeanEntries) { Map> factories = transform(configRegistryClient, mBeanEntries); + return new Config(factories); } // TODO refactor - private static Map> transform(final ConfigRegistryClient configRegistryClient, - Map> mBeanEntries) { + private static Map> transform + (final ConfigRegistryClient configRegistryClient, Map> mBeanEntries) { return Maps.transformEntries(mBeanEntries, new Maps.EntryTransformer, Map>() { @@ -164,9 +169,9 @@ public class EditConfig extends AbstractConfigNetconfOperation { new Maps.EntryTransformer() { @Override - public ModuleConfig transformEntry(String key, ModuleMXBeanEntry value) { - return new ModuleConfig(key, new InstanceConfig(configRegistryClient, value - .getAttributes())); + public ModuleConfig transformEntry(String key, ModuleMXBeanEntry moduleMXBeanEntry) { + return new ModuleConfig(key, new InstanceConfig(configRegistryClient, moduleMXBeanEntry + .getAttributes()), moduleMXBeanEntry.getProvidedServices().values()); } }); } @@ -184,7 +189,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { EditConfigXmlParser.EditConfigExecution editConfigExecution; Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap()); try { - editConfigExecution = editConfigXmlParser.fromXml(xml, cfg); + editConfigExecution = editConfigXmlParser.fromXml(xml, cfg, transactionProvider, configRegistryClient); } catch (IllegalStateException e) { logger.warn("Error parsing xml", e); final Map errorInfo = new HashMap<>(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java index d835dfd30f..3d4e5b6d0c 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java @@ -12,17 +12,22 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Multimap; +import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; +import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.ObjectName; import java.util.Arrays; +import java.util.Collections; import java.util.Map; +import java.util.Set; public class EditConfigXmlParser { @@ -38,10 +43,11 @@ public class EditConfigXmlParser { public EditConfigXmlParser() { } - EditConfigXmlParser.EditConfigExecution fromXml(final XmlElement xml, final Config cfgMapping) + EditConfigXmlParser.EditConfigExecution fromXml(final XmlElement xml, final Config cfgMapping, + TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient) throws NetconfDocumentedException { - EditStrategyType.resetDefaultStrategy(); + EditStrategyType editStrategyType = EditStrategyType.getDefaultStrategy(); xml.checkName(EditConfigXmlParser.EDIT_CONFIG); xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); @@ -81,12 +87,22 @@ public class EditConfigXmlParser { // Default op Optional defaultContent = xml .getOnlyChildElementWithSameNamespaceOptionally(EditConfigXmlParser.DEFAULT_OPERATION_KEY); - if (defaultContent.isPresent()) - EditStrategyType.setDefaultStrategy(EditStrategyType.valueOf(defaultContent.get().getTextContent())); + if (defaultContent.isPresent()) { + String mergeStrategyString = defaultContent.get().getTextContent(); + logger.trace("Setting merge strategy to {}", mergeStrategyString); + editStrategyType = EditStrategyType.valueOf(mergeStrategyString); + } + Set instancesForFillingServiceRefMapping = Collections.emptySet(); + if (editStrategyType == EditStrategyType.merge) { + instancesForFillingServiceRefMapping = Datastore.getInstanceQueryStrategy(targetDatastore, transactionProvider) + .queryInstances(configRegistryClient); + logger.trace("Pre-filling services from following instances: {}", instancesForFillingServiceRefMapping); + } XmlElement configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY); - return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption); + return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption, + instancesForFillingServiceRefMapping, editStrategyType); } private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) { @@ -119,14 +135,17 @@ public class EditConfigXmlParser { @VisibleForTesting static class EditConfigExecution { - XmlElement editConfigXml; - Map> resolvedXmlElements; - TestOption testOption; + private final XmlElement editConfigXml; + private final Map> resolvedXmlElements; + private final TestOption testOption; + private final EditStrategyType defaultEditStrategyType; - EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption) { + EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set instancesForFillingServiceRefMapping, + EditStrategyType defaultStrategy) { this.editConfigXml = xml; - this.resolvedXmlElements = configResolver.fromXml(configElement); + this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping, defaultStrategy); this.testOption = testOption; + this.defaultEditStrategyType = defaultStrategy; } boolean shouldTest() { @@ -136,5 +155,13 @@ public class EditConfigXmlParser { boolean shouldSet() { return testOption == TestOption.set || testOption == TestOption.testThenSet; } + + Map> getResolvedXmlElements() { + return resolvedXmlElements; + } + + EditStrategyType getDefaultStrategy() { + return defaultEditStrategyType; + } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java index a7a0518cc5..cb03342a1e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java @@ -11,8 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed import java.util.EnumSet; import java.util.Set; -import com.google.common.base.Preconditions; - +//FIXME: make thread safe public enum EditStrategyType { // can be default merge, replace, none, @@ -21,20 +20,8 @@ public enum EditStrategyType { private static final Set defaultStrats = EnumSet.of(merge, replace, none); - private static EditStrategyType defaultStrat = merge; - - public static EditStrategyType defaultStrategy() { - return defaultStrat; - } - - public static void setDefaultStrategy(EditStrategyType strat) { - Preconditions.checkArgument(strat.canBeDefault(), "Default edit strategy can be only of value " + defaultStrats - + ", but was " + strat); - defaultStrat = strat; - } - - public static void resetDefaultStrategy() { - setDefaultStrategy(EditStrategyType.merge); + public static EditStrategyType getDefaultStrategy() { + return merge; } public boolean isEnforcing() { @@ -53,16 +40,6 @@ public enum EditStrategyType { } } - private static final EnumSet defaults; - - static { - defaults = EnumSet.of(merge, replace, none); - } - - private boolean canBeDefault() { - return defaults.contains(this); - } - public EditConfigStrategy getFittingStrategy() { switch (this) { case merge: diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java index 9b8c1503c7..79b3e26aec 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java @@ -80,6 +80,7 @@ public class GetConfig extends AbstractConfigNetconfOperation { Element dataElement = document.createElement(XmlNetconfConstants.DATA_KEY); final Set instances = Datastore.getInstanceQueryStrategy(source, this.transactionProvider) .queryInstances(configRegistryClient); + final Config configMapping = new Config(transform(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap())); dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java index f838c6f9f5..7463bdd429 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpc.java @@ -127,6 +127,7 @@ public class RuntimeRpc extends AbstractConfigNetconfOperation { if (contextInstanceElement.isPresent() == false) return HandlingPriority.CANNOT_HANDLE; + // FIXME update xpath to instance to conform to config-api yang final RuntimeRpcElementResolved id = RuntimeRpcElementResolved.fromXpath(contextInstanceElement.get() .getTextContent(), netconfOperationName, netconfOperationNamespace); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java index 838e5d8731..0f0b1227a6 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/runtimerpc/RuntimeRpcElementResolved.java @@ -33,11 +33,11 @@ public final class RuntimeRpcElementResolved { private RuntimeRpcElementResolved(String namespace, String moduleName, String instanceName, String runtimeBeanName, Map additionalAttributes) { - this.moduleName = moduleName; - this.instanceName = instanceName; + this.moduleName = Preconditions.checkNotNull(moduleName, "Module name"); + this.instanceName = Preconditions.checkNotNull(instanceName, "Instance name"); this.additionalAttributes = additionalAttributes; - this.namespace = namespace; - this.runtimeBeanName = runtimeBeanName; + this.namespace = Preconditions.checkNotNull(namespace, "Namespace"); + this.runtimeBeanName = Preconditions.checkNotNull(runtimeBeanName, "Runtime bean name"); } public String getModuleName() { @@ -68,12 +68,22 @@ public final class RuntimeRpcElementResolved { return ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, additionalAttributesJavaNames); } - private static final String xpathPatternBlueprint = "/" + XmlNetconfConstants.DATA_KEY + "/" - + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\[" - + XmlNetconfConstants.NAME_KEY + "='(.+)'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\[" - + XmlNetconfConstants.NAME_KEY + "='([^']+)'\\](.*)"; + private static final String xpathPatternBlueprint = + "/" + XmlNetconfConstants.MODULES_KEY + + "/" + XmlNetconfConstants.MODULE_KEY + + "\\[" + + + "(?type|name)" + + "='(?[^']+)'" + + "( and |\\]\\[)" + + "(?type|name)" + + "='(?[^']+)'" + + + "\\]" + + "(?.*)"; + private static final Pattern xpathPattern = Pattern.compile(xpathPatternBlueprint); - private static final String additionalPatternBlueprint = "(.+)\\[(.+)='(.+)'\\]"; + private static final String additionalPatternBlueprint = "(?.+)\\[(.+)='(?.+)'\\]"; private static final Pattern additionalPattern = Pattern.compile(additionalPatternBlueprint); public static RuntimeRpcElementResolved fromXpath(String xpath, String elementName, String namespace) { @@ -82,26 +92,65 @@ public final class RuntimeRpcElementResolved { "Node %s with value '%s' not in required form on rpc element %s, required format is %s", RuntimeRpc.CONTEXT_INSTANCE, xpath, elementName, xpathPatternBlueprint); - String moduleName = matcher.group(1); - String instanceName = matcher.group(2); - String additionalString = matcher.group(3); - HashMap additionalAttributes = Maps. newHashMap(); - String runtimeBeanYangName = moduleName; - for (String additionalKeyValue : additionalString.split("/")) { - if (Strings.isNullOrEmpty(additionalKeyValue)) - continue; - matcher = additionalPattern.matcher(additionalKeyValue); - Preconditions - .checkState( - matcher.matches(), - "Attribute %s not in required form on rpc element %s, required format for additional attributes is %s", - additionalKeyValue, elementName, additionalPatternBlueprint); - String name = matcher.group(1); - runtimeBeanYangName = name; - additionalAttributes.put(name, matcher.group(3)); - } + PatternGroupResolver groups = new PatternGroupResolver(matcher.group("key1"), matcher.group("value1"), + matcher.group("key2"), matcher.group("value2"), matcher.group("additional")); + + String moduleName = groups.getModuleName(); + String instanceName = groups.getInstanceName(); + + HashMap additionalAttributes = groups.getAdditionalKeys(elementName, moduleName); - return new RuntimeRpcElementResolved(namespace, moduleName, instanceName, runtimeBeanYangName, + return new RuntimeRpcElementResolved(namespace, moduleName, instanceName, groups.getRuntimeBeanYangName(), additionalAttributes); } + + private static final class PatternGroupResolver { + + private final String key1, key2, value1, value2; + private final String additional; + private String runtimeBeanYangName; + + PatternGroupResolver(String key1, String value1, String key2, String value2, String additional) { + this.key1 = Preconditions.checkNotNull(key1); + this.value1 = Preconditions.checkNotNull(value1); + + this.key2 = Preconditions.checkNotNull(key2); + this.value2 = Preconditions.checkNotNull(value2); + + this.additional = Preconditions.checkNotNull(additional); + } + + String getModuleName() { + return key1.equals(XmlNetconfConstants.TYPE_KEY) ? value1 : value2; + } + + String getInstanceName() { + return key1.equals(XmlNetconfConstants.NAME_KEY) ? value1 : value2; + } + + HashMap getAdditionalKeys(String elementName, String moduleName) { + HashMap additionalAttributes = Maps.newHashMap(); + + runtimeBeanYangName = moduleName; + for (String additionalKeyValue : additional.split("/")) { + if (Strings.isNullOrEmpty(additionalKeyValue)) + continue; + Matcher matcher = additionalPattern.matcher(additionalKeyValue); + Preconditions + .checkState( + matcher.matches(), + "Attribute %s not in required form on rpc element %s, required format for additional attributes is %s", + additionalKeyValue, elementName, additionalPatternBlueprint); + String name = matcher.group("additionalKey"); + runtimeBeanYangName = name; + additionalAttributes.put(name, matcher.group("additionalValue")); + } + return additionalAttributes; + } + + private String getRuntimeBeanYangName() { + Preconditions.checkState(runtimeBeanYangName!=null); + return runtimeBeanYangName; + } + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java index b3483a737a..b8113a0903 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java @@ -41,12 +41,12 @@ public class TransactionProvider implements AutoCloseable { @Override public synchronized void close() { for (ObjectName tx : allOpenedTransactions) { - if (isStillOpenTransaction(tx)) { - try { + try { + if (isStillOpenTransaction(tx)) { configRegistryClient.getConfigTransactionClient(tx).abortConfig(); - } catch (Exception e) { - logger.debug("Ignoring {} while closing transaction {}", e.toString(), tx, e); } + } catch (Exception e) { + logger.debug("Ignoring exception while closing transaction {}", tx, e); } } allOpenedTransactions.clear(); diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index d404a96468..296b224fff 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -143,6 +143,7 @@ public class NetconfMappingTest extends AbstractConfigTest { edit("netconfMessages/editConfig.xml"); checkBinaryLeafEdited(getConfigCandidate()); + // default-operation:none, should not affect binary leaf edit("netconfMessages/editConfig_none.xml"); checkBinaryLeafEdited(getConfigCandidate()); @@ -150,7 +151,6 @@ public class NetconfMappingTest extends AbstractConfigTest { // check after edit commit(); Element response = getConfigRunning(); - // System.out.println(Xml.toString(response)); checkBinaryLeafEdited(response); checkTypeConfigAttribute(response); @@ -441,7 +441,9 @@ public class NetconfMappingTest extends AbstractConfigTest { Element response = get(); - assertEquals(2, getElementsSize(response, "instance")); + System.err.println(XmlUtil.toString(response)); + + assertEquals(2, getElementsSize(response, "module")); assertEquals(2, getElementsSize(response, "asdf")); assertEquals(5, getElementsSize(response, "inner-running-data")); assertEquals(5, getElementsSize(response, "deep2")); diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java index e07f9ce3e1..425ecf6d02 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java @@ -1,10 +1,10 @@ /* - * 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 - */ +* 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.netconf.confignetconfconnector; @@ -31,41 +31,41 @@ public class ServiceTrackerTest { @Test public void testOneInstanceMultipleServices() { Services services = new Services(); - services.addServiceEntry("s1", "module", "instance"); + services.addServiceEntry("nm", "s1", "module", "instance"); assertEquals(1, services.getMappedServices().size()); - services.addServiceEntry("s2", "module", "instance"); + services.addServiceEntry("nm2", "s2", "module", "instance"); assertEquals(2, services.getMappedServices().size()); } @Test public void testMultipleInstancesOneName() throws Exception { Services services = new Services(); - services.addServiceEntry("s1", "module", "instance"); + services.addServiceEntry("nm", "s1", "module", "instance"); assertEquals(1, services.getMappedServices().size()); - services.addServiceEntry("s1", "module2", "instance"); + services.addServiceEntry("nm", "s1", "module2", "instance"); assertEquals(1, services.getMappedServices().size()); - assertEquals(2, services.getMappedServices().get("s1").size()); - assertTrue(services.getMappedServices().get("s1").containsKey("ref_instance")); - assertTrue(services.getMappedServices().get("s1").containsKey("ref_instance_1")); + assertEquals(2, services.getMappedServices().get("nm").get("s1").size()); + assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance")); + assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1")); } @Test public void testMultipleInstancesOneName2() throws Exception { Services services = new Services(); - services.addServiceEntry("s1", "module", "instance_1"); - - services.addServiceEntry("s2", "module2", "instance"); - services.addServiceEntry("s2", "module3", "instance"); - services.addServiceEntry("s1", "module3", "instance"); - - assertEquals(2, services.getMappedServices().get("s1").size()); - assertEquals(2, services.getMappedServices().get("s2").size()); - assertTrue(services.getMappedServices().get("s1").containsKey("ref_instance_2")); - assertTrue(services.getMappedServices().get("s1").containsKey("ref_instance_1")); - assertTrue(services.getMappedServices().get("s2").containsKey("ref_instance")); - assertTrue(services.getMappedServices().get("s2").containsKey("ref_instance_2")); + services.addServiceEntry("nm", "s1", "module", "instance_1"); + + services.addServiceEntry("nm2", "s2", "module2", "instance"); + services.addServiceEntry("nm2", "s2", "module3", "instance"); + services.addServiceEntry("nm", "s1", "module3", "instance"); + + assertEquals(2, services.getMappedServices().get("nm").get("s1").size()); + assertEquals(2, services.getMappedServices().get("nm2").get("s2").size()); + assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_2")); + assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1")); + assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance")); + assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance_2")); } } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java index 123c03e9a1..1b8e24702a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java @@ -31,7 +31,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import javax.management.ObjectName; +import java.util.Collections; import java.util.Map; +import java.util.Set; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; @@ -86,10 +88,12 @@ public class EditConfigTest { Config cfg = mock(Config.class); XmlElement xmlElement = mock(XmlElement.class); - doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement); + Set instancesForFillingServiceRefMapping = Collections.emptySet(); + EditStrategyType defaultStrategy = EditStrategyType.getDefaultStrategy(); + doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping, defaultStrategy); EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement, - EditConfigXmlParser.TestOption.testThenSet); + EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping, defaultStrategy); edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution); diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java index a20e00bcff..25d2ad6abd 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.util.Collections; +import java.util.HashSet; import java.util.Set; /** @@ -54,9 +55,9 @@ public class ConfigPersisterNotificationHandler implements NotificationListener, private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class); private final InetSocketAddress address; - private final NetconfClientDispatcher dispatcher; private final EventLoopGroup nettyThreadgroup; + private NetconfClientDispatcher netconfClientDispatcher; private NetconfClient netconfClient; private final Persister persister; @@ -81,7 +82,6 @@ public class ConfigPersisterNotificationHandler implements NotificationListener, this.timeout = timeout; this.nettyThreadgroup = new NioEventLoopGroup(); - this.dispatcher = new NetconfClientDispatcher(Optional.absent(), nettyThreadgroup, nettyThreadgroup); } public void init() throws InterruptedException { @@ -125,11 +125,12 @@ public class ConfigPersisterNotificationHandler implements NotificationListener, while (true) { attempt++; + netconfClientDispatcher = new NetconfClientDispatcher(Optional.absent(), nettyThreadgroup, nettyThreadgroup); try { - netconfClient = new NetconfClient(this.toString(), address, delay, dispatcher); - // TODO is this correct ex to catch ? + netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher); } catch (IllegalStateException e) { logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e); + netconfClientDispatcher.close(); Thread.sleep(delay); continue; } @@ -148,18 +149,35 @@ public class ConfigPersisterNotificationHandler implements NotificationListener, logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, currentCapabilities); - try { - netconfClient.close(); - } catch (IOException e) { - throw new RuntimeException("Error closing temporary client " + netconfClient); - } + closeClientAndDispatcher(netconfClient, netconfClientDispatcher); Thread.sleep(delay); } + Set allNotFound = new HashSet<>(expectedCaps); + allNotFound.removeAll(currentCapabilities); + logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}", + allNotFound, expectedCaps ,currentCapabilities); + throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound); - throw new RuntimeException("Netconf server did not provide required capabilities " + expectedCaps - + " in time, provided capabilities " + currentCapabilities); + } + private static void closeClientAndDispatcher(Closeable client, Closeable dispatcher) { + Exception fromClient = null; + try { + client.close(); + } catch (Exception e) { + fromClient = e; + } finally { + try { + dispatcher.close(); + } catch (Exception e) { + if (fromClient != null) { + e.addSuppressed(fromClient); + } + + throw new RuntimeException("Error closing temporary client ", e); + } + } } private boolean isSubset(Set currentCapabilities, Set expectedCaps) { @@ -318,10 +336,18 @@ public class ConfigPersisterNotificationHandler implements NotificationListener, } } + if (netconfClientDispatcher != null) { + try { + netconfClientDispatcher.close(); + } catch (Exception e) { + logger.warn("Unable to close connection to netconf {}", netconfClientDispatcher, e); + } + } + try { nettyThreadgroup.shutdownGracefully(); } catch (Exception e) { - logger.warn("Unable to close netconf client thread group {}", dispatcher, e); + logger.warn("Unable to close netconf client thread group {}", netconfClientDispatcher, e); } // unregister from JMX diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java index 6fc4da026f..62c2113056 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java @@ -23,20 +23,27 @@ import org.opendaylight.protocol.framework.AbstractDispatcher; import org.opendaylight.protocol.framework.ReconnectStrategy; import org.opendaylight.protocol.framework.SessionListener; import org.opendaylight.protocol.framework.SessionListenerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; +import java.io.Closeable; import java.net.InetSocketAddress; -public class NetconfClientDispatcher extends AbstractDispatcher { +public class NetconfClientDispatcher extends AbstractDispatcher implements Closeable { + + private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class); private final Optional maybeContext; private final NetconfClientSessionNegotiatorFactory negotatorFactory; + private final HashedWheelTimer timer; public NetconfClientDispatcher(final Optional maybeContext, EventLoopGroup bossGroup, EventLoopGroup workerGroup) { super(bossGroup, workerGroup); this.maybeContext = Preconditions.checkNotNull(maybeContext); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer()); + timer = new HashedWheelTimer(); + this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer); } public Future createClient(InetSocketAddress address, @@ -83,4 +90,12 @@ public class NetconfClientDispatcher extends AbstractDispatcher errorInfo = Maps.newHashMap(); + + NetconfDocumentedException.ErrorTag tag = null; + if (e instanceof IllegalArgumentException) { + errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage()); + tag = NetconfDocumentedException.ErrorTag.operation_not_supported; + } else if (e instanceof IllegalStateException) { + errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage()); + tag = NetconfDocumentedException.ErrorTag.operation_failed; + } + + throw new NetconfDocumentedException(errorMessage, e, NetconfDocumentedException.ErrorType.application, + tag, NetconfDocumentedException.ErrorSeverity.error, errorInfo); + } catch (RuntimeException e) { + throw handleUnexpectedEx("Unexpected exception during netconf operation sort", e); + } + + try { + return executeOperationWithHighestPriority(message, netconfOperationExecution, messageAsString); + } catch (RuntimeException e) { + throw handleUnexpectedEx("Unexpected exception during netconf operation execution", e); + } + } + + private NetconfDocumentedException handleUnexpectedEx(String s, Exception e) throws NetconfDocumentedException { + logger.error(s, e); + + Map info = Maps.newHashMap(); + info.put(NetconfDocumentedException.ErrorSeverity.error.toString(), e.toString()); + return new NetconfDocumentedException("Unexpected error", + NetconfDocumentedException.ErrorType.application, + NetconfDocumentedException.ErrorTag.operation_failed, + NetconfDocumentedException.ErrorSeverity.error, info); + } + + private Document executeOperationWithHighestPriority(Document message, NetconfOperationExecution netconfOperationExecution, String messageAsString) throws NetconfDocumentedException { + logger.debug("Forwarding netconf message {} to {}", messageAsString, netconfOperationExecution.operationWithHighestPriority); final LinkedList chain = new LinkedList<>(); @@ -147,7 +191,7 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { TreeMap> sortedPriority = getSortedNetconfOperationsWithCanHandle( message, session); - Preconditions.checkState(sortedPriority.isEmpty() == false, "No %s available to handle message %s", + Preconditions.checkArgument(sortedPriority.isEmpty() == false, "No %s available to handle message %s", NetconfOperation.class.getName(), XmlUtil.toString(message)); HandlingPriority highestFoundPriority = sortedPriority.lastKey(); diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java index 403ba3d0fc..c03254dba2 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java @@ -134,6 +134,7 @@ public class NetconfITTest extends AbstractConfigTest { public void tearDown() throws Exception { commitNot.close(); nettyThreadgroup.shutdownGracefully(); + clientDispatcher.close(); } private void loadMessages() throws IOException, SAXException, ParserConfigurationException { @@ -274,7 +275,7 @@ public class NetconfITTest extends AbstractConfigTest { + " " - + "/data/modules/module[name='impl-netconf']/instance[name='instance']" + + "/modules/module[type='impl-netconf'][name='instance']" + "argument1" + "" + ""; final Document doc = XmlUtil.readXmlToDocument(rpc); final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc)); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java index c37b4abc62..212214cd2a 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java @@ -326,7 +326,7 @@ public class XmlElement { prefix = ""; } if (namespaces.containsKey(prefix) == false) { - throw new IllegalArgumentException("Cannot find namespace for " + element + ". Prefix from content is " + throw new IllegalArgumentException("Cannot find namespace for " + XmlUtil.toString(element) + ". Prefix from content is " + prefix + ". Found namespaces " + namespaces); } return Maps.immutableEntry(prefix, namespaces.get(prefix)); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlNetconfConstants.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlNetconfConstants.java index 2a900e052b..7fb293f054 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlNetconfConstants.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlNetconfConstants.java @@ -33,6 +33,8 @@ public class XmlNetconfConstants { public static final String NAME_KEY = "name"; public static final String NOTIFICATION_ELEMENT_NAME = "notification"; + public static final String PREFIX = "prefix"; + // // public static final String RFC4741_TARGET_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0"; diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml index 904c0a6322..0611dceb3a 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml @@ -75,7 +75,7 @@ 44 - testing + prefix:testing ref_dep @@ -86,7 +86,7 @@ test2 - testing + prefix:testing ref_dep @@ -94,7 +94,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml index 42021c59a3..c825536b7b 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml @@ -69,7 +69,7 @@ 44 - testing + prefix:testing ref_dep @@ -79,14 +79,14 @@ test2 - testing + prefix:testing ref_dep - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_differentNamespaceTO.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_differentNamespaceTO.xml index efa4690f6f..82c218dd73 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_differentNamespaceTO.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_differentNamespaceTO.xml @@ -75,7 +75,7 @@ 44 - testing + prefix:testing ref_dep @@ -86,7 +86,7 @@ test2 - testing + prefix:testing ref_dep @@ -94,7 +94,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml index 3dbb297c29..7c19b9f7b3 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml @@ -76,7 +76,7 @@ 44 - testing + prefix:testing ref_dep @@ -87,7 +87,7 @@ test2 - testing + prefix:testing ref_dep @@ -95,7 +95,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml index 504ccff78f..84ae575559 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml @@ -75,7 +75,7 @@ 44 - testing + prefix:testing ref_dep @@ -86,7 +86,7 @@ test2 - testing + prefix:testing ref_dep @@ -94,7 +94,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml index 8398fdb588..2d9e9edb2c 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml @@ -74,7 +74,7 @@ 44 - testing + prefix:testing ref_dep @@ -85,7 +85,7 @@ test2 - testing + prefix:testing ref_dep @@ -93,7 +93,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml index b2a2ee30c8..413b78c5d3 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml @@ -1,6 +1,6 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance'] + /modules/module[type='impl-netconf' and name='instance'] testarg1 diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml index 8bc504a56e..cf15000b1a 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml @@ -1,7 +1,7 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance2']/inner-running-data-additional[key='randomString_1003'] + /modules/module[name='instance2'][type='impl-netconf']/inner-running-data-additional[key='randomString_1003'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml index 2356398e64..31f417e879 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml @@ -2,7 +2,7 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] + /modules/module[type='impl-netconf'][name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml index 209c382252..af0835b5df 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml @@ -2,7 +2,7 @@ - /data/modules/module[name='impl-netconf']/instance[name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] + /modules/module[type='impl-netconf'][name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised1.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised1.xml index 6b267c57a3..e675e86d07 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised1.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised1.xml @@ -23,7 +23,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised2.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised2.xml index 8ca7ee724a..9407dd0c75 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised2.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised2.xml @@ -24,7 +24,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised3.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised3.xml index d3705cc3c4..233ad23286 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised3.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised3.xml @@ -25,7 +25,7 @@ error l - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised4.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised4.xml index a485574969..4593887f49 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised4.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised4.xml @@ -24,7 +24,7 @@ l - testing + prefix:testing error diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised5.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised5.xml index 654a183359..81c4137d4e 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised5.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised5.xml @@ -24,7 +24,7 @@ l - testing + prefix:testing ref_dep diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised6.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised6.xml index fc43a77406..528d5b06fc 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised6.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised6.xml @@ -23,7 +23,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised7.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised7.xml index 1bea536934..a1e304b374 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised7.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised7.xml @@ -75,7 +75,7 @@ 44 - testing + prefix:testing ref_dep @@ -86,7 +86,7 @@ test2 - testing + prefix:testing ref_dep @@ -94,7 +94,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised8.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised8.xml index d0afb276aa..812882a2a9 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised8.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised8.xml @@ -75,7 +75,7 @@ error - testing + prefix:testing ref_dep @@ -86,7 +86,7 @@ test2 - testing + prefix:testing ref_dep @@ -94,7 +94,7 @@ - testing + prefix:testing ref_dep /config/modules/module[name='impl-dep']/instance[name='dep'] diff --git a/opendaylight/northbound/hosttracker/pom.xml b/opendaylight/northbound/hosttracker/pom.xml index 040484e695..541dfcfe2d 100644 --- a/opendaylight/northbound/hosttracker/pom.xml +++ b/opendaylight/northbound/hosttracker/pom.xml @@ -79,7 +79,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/northbound/integrationtest/pom.xml b/opendaylight/northbound/integrationtest/pom.xml index 4b79865ca9..b4e0b34d09 100644 --- a/opendaylight/northbound/integrationtest/pom.xml +++ b/opendaylight/northbound/integrationtest/pom.xml @@ -69,7 +69,7 @@ org.opendaylight.controller forwarding.staticrouting - 0.4.1-SNAPSHOT + ${forwarding.staticrouting} org.opendaylight.controller @@ -99,7 +99,7 @@ org.opendaylight.controller arphandler - 0.4.1-SNAPSHOT + ${arphandler.version} org.opendaylight.controller @@ -114,12 +114,12 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller hosttracker.implementation - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/northbound/staticrouting/pom.xml b/opendaylight/northbound/staticrouting/pom.xml index a869519c58..d169de9f2a 100644 --- a/opendaylight/northbound/staticrouting/pom.xml +++ b/opendaylight/northbound/staticrouting/pom.xml @@ -84,7 +84,7 @@ org.opendaylight.controller forwarding.staticrouting - 0.4.1-SNAPSHOT + ${forwarding.staticrouting} org.codehaus.enunciate diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java index b163c639a5..f26bcf718c 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java @@ -415,7 +415,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, */ if (inPort == null || container.equals(GlobalConstants.DEFAULT.toString()) - || this.containerToNc.get(container).contains(inPort)) { + || (containerToNc.containsKey(container) && containerToNc.get(container).contains(inPort))) { notifier.flowRemoved(node, flow); } } diff --git a/opendaylight/samples/loadbalancer/pom.xml b/opendaylight/samples/loadbalancer/pom.xml index 69163c6939..cf7a18ea65 100644 --- a/opendaylight/samples/loadbalancer/pom.xml +++ b/opendaylight/samples/loadbalancer/pom.xml @@ -15,7 +15,7 @@ samples.loadbalancer - 0.4.1-SNAPSHOT + 0.5.1-SNAPSHOT bundle @@ -90,7 +90,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java index 1e3b845b86..b2229cb022 100644 --- a/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java +++ b/opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/internal/LoadBalancerService.java @@ -17,6 +17,8 @@ import java.util.Set; import org.apache.felix.dm.Component; import org.opendaylight.controller.forwardingrulesmanager.FlowEntry; import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager; +import org.opendaylight.controller.hosttracker.HostIdFactory; +import org.opendaylight.controller.hosttracker.IHostId; import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector; import org.opendaylight.controller.sal.action.Action; @@ -56,35 +58,36 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * This class is the main class that represents the load balancer service. - * This is a sample load balancer application that balances traffic to backend servers - * based on the source address and source port on each incoming packet. The service - * reactively installs OpenFlow rules to direct all packets with a specific source address - * and source port to one of the appropriate backend servers. The servers may be chosen - * using a round robin policy or a random policy. This service can be configured via a - * REST APIs which are similar to the OpenStack Quantum LBaaS (Load-balancer-as-a-Service) - * v1.0 API proposal (http://wiki.openstack.org/Quantum/LBaaS) + * This class is the main class that represents the load balancer service. This + * is a sample load balancer application that balances traffic to backend + * servers based on the source address and source port on each incoming packet. + * The service reactively installs OpenFlow rules to direct all packets with a + * specific source address and source port to one of the appropriate backend + * servers. The servers may be chosen using a round robin policy or a random + * policy. This service can be configured via a REST APIs which are similar to + * the OpenStack Quantum LBaaS (Load-balancer-as-a-Service) v1.0 API proposal + * (http://wiki.openstack.org/Quantum/LBaaS) * - * To use this service, a virtual IP (or VIP) should be exposed to the clients of this service - * and used as the destination address. A VIP is a entity that comprises of a virtual IP, port - * and protocol (TCP or UDP). - * Assumptions: - * 1. One or more VIPs may be mapped to the same server pool. All VIPs that share the same - * pool must also share the same load balancing policy (random or round robin). + * To use this service, a virtual IP (or VIP) should be exposed to the clients + * of this service and used as the destination address. A VIP is a entity that + * comprises of a virtual IP, port and protocol (TCP or UDP). Assumptions: 1. + * One or more VIPs may be mapped to the same server pool. All VIPs that share + * the same pool must also share the same load balancing policy (random or round + * robin). * - * 2. Only one server pool can be be assigned to a VIP. + * 2. Only one server pool can be be assigned to a VIP. * - * 3. All flow rules are installed with an idle timeout of 5 seconds. + * 3. All flow rules are installed with an idle timeout of 5 seconds. * - * 4. Packets to a VIP must leave the OpenFlow cluster from the same switch from where - * it entered it. + * 4. Packets to a VIP must leave the OpenFlow cluster from the same switch from + * where it entered it. * - * 5. When you delete a VIP or a server pool or a server from a pool, the service does not - * delete the flow rules it has already installed. The flow rules should automatically - * time out after the idle timeout of 5 seconds. + * 5. When you delete a VIP or a server pool or a server from a pool, the + * service does not delete the flow rules it has already installed. The flow + * rules should automatically time out after the idle timeout of 5 seconds. * */ -public class LoadBalancerService implements IListenDataPacket, IConfigManager{ +public class LoadBalancerService implements IListenDataPacket, IConfigManager { /* * Logger instance @@ -92,8 +95,8 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ private static Logger lbsLogger = LoggerFactory.getLogger(LoadBalancerService.class); /* - * Single instance of the configuration manager. Application passes this reference to all - * the new policies implemented for load balancing. + * Single instance of the configuration manager. Application passes this + * reference to all the new policies implemented for load balancing. */ private static ConfigManager configManager = new ConfigManager(); @@ -101,12 +104,12 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ * Round robing policy instance. Need to implement factory patterns to get * policy instance. */ - private static RoundRobinLBPolicy rrLBMethod= new RoundRobinLBPolicy(configManager); + private static RoundRobinLBPolicy rrLBMethod = new RoundRobinLBPolicy(configManager); /* * Random policy instance. */ - private static RandomLBPolicy ranLBMethod= new RandomLBPolicy(configManager); + private static RandomLBPolicy ranLBMethod = new RandomLBPolicy(configManager); /* * Reference to the data packet service @@ -139,8 +142,8 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ private String containerName = null; /* - * Set/unset methods for the service instance that load balancer - * service requires + * Set/unset methods for the service instance that load balancer service + * requires */ public String getContainerName() { if (containerName == null) @@ -179,32 +182,30 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ } } - public void setForwardingRulesManager( - IForwardingRulesManager forwardingRulesManager) { + public void setForwardingRulesManager(IForwardingRulesManager forwardingRulesManager) { lbsLogger.debug("Setting ForwardingRulesManager"); this.ruleManager = forwardingRulesManager; } - public void unsetForwardingRulesManager( - IForwardingRulesManager forwardingRulesManager) { + public void unsetForwardingRulesManager(IForwardingRulesManager forwardingRulesManager) { if (this.ruleManager == forwardingRulesManager) { this.ruleManager = null; } } /** - * This method receives first packet of flows for which there is no - * matching flow rule installed on the switch. IP addresses used for VIPs - * are not supposed to be used by any real/virtual host in the network. - * Hence, any forwarding/routing service will not install any flows rules matching - * these VIPs. This ensures that all the flows destined for VIPs will not find a match - * in the switch and will be forwarded to the load balancing service. - * Service will decide where to route this traffic based on the load balancing - * policy of the VIP's attached pool and will install appropriate flow rules - * in a reactive manner. + * This method receives first packet of flows for which there is no matching + * flow rule installed on the switch. IP addresses used for VIPs are not + * supposed to be used by any real/virtual host in the network. Hence, any + * forwarding/routing service will not install any flows rules matching + * these VIPs. This ensures that all the flows destined for VIPs will not + * find a match in the switch and will be forwarded to the load balancing + * service. Service will decide where to route this traffic based on the + * load balancing policy of the VIP's attached pool and will install + * appropriate flow rules in a reactive manner. */ @Override - public PacketResult receiveDataPacket(RawPacket inPkt){ + public PacketResult receiveDataPacket(RawPacket inPkt) { if (inPkt == null) { return PacketResult.IGNORED; @@ -218,88 +219,89 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ if (ipPkt instanceof IPv4) { - lbsLogger.debug("Packet recieved from switch : {}",inPkt.getIncomingNodeConnector().getNode().toString()); - IPv4 ipv4Pkt = (IPv4)ipPkt; - if(IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.TCP.toString()) - || IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.UDP.toString())){ + lbsLogger.debug("Packet recieved from switch : {}", inPkt.getIncomingNodeConnector().getNode() + .toString()); + IPv4 ipv4Pkt = (IPv4) ipPkt; + if (IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.TCP.toString()) + || IPProtocols.getProtocolName(ipv4Pkt.getProtocol()).equals(IPProtocols.UDP.toString())) { - lbsLogger.debug("Packet protocol : {}",IPProtocols.getProtocolName(ipv4Pkt.getProtocol())); + lbsLogger.debug("Packet protocol : {}", IPProtocols.getProtocolName(ipv4Pkt.getProtocol())); Client client = new LBUtil().getClientFromPacket(ipv4Pkt); VIP vip = new LBUtil().getVIPFromPacket(ipv4Pkt); - if(configManager.vipExists(vip)){ + if (configManager.vipExists(vip)) { VIP vipWithPoolName = configManager.getVIPWithPoolName(vip); String poolMemberIp = null; - if(vipWithPoolName.getPoolName() == null){ - lbsLogger.error("No pool attached. Please attach pool with the VIP -- {}",vip); + if (vipWithPoolName.getPoolName() == null) { + lbsLogger.error("No pool attached. Please attach pool with the VIP -- {}", vip); return PacketResult.IGNORED; } - if(configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod().equalsIgnoreCase(LBConst.ROUND_ROBIN_LB_METHOD)){ + if (configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod() + .equalsIgnoreCase(LBConst.ROUND_ROBIN_LB_METHOD)) { - poolMemberIp = rrLBMethod.getPoolMemberForClient(client,vipWithPoolName); + poolMemberIp = rrLBMethod.getPoolMemberForClient(client, vipWithPoolName); } - if(configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod().equalsIgnoreCase(LBConst.RANDOM_LB_METHOD)){ - poolMemberIp = ranLBMethod.getPoolMemberForClient(client,vipWithPoolName); + if (configManager.getPool(vipWithPoolName.getPoolName()).getLbMethod() + .equalsIgnoreCase(LBConst.RANDOM_LB_METHOD)) { + poolMemberIp = ranLBMethod.getPoolMemberForClient(client, vipWithPoolName); } try { Node clientNode = inPkt.getIncomingNodeConnector().getNode(); - HostNodeConnector hnConnector = this.hostTracker.hostFind(InetAddress.getByName(poolMemberIp)); + // HostTracker hosts db key scheme implementation + IHostId id = HostIdFactory.create(InetAddress.getByName(poolMemberIp), null); + HostNodeConnector hnConnector = this.hostTracker.hostFind(id); Node destNode = hnConnector.getnodeconnectorNode(); - lbsLogger.debug("Client is connected to switch : {}",clientNode.toString()); - lbsLogger.debug("Destination pool machine is connected to switch : {}",destNode.toString()); + lbsLogger.debug("Client is connected to switch : {}", clientNode.toString()); + lbsLogger + .debug("Destination pool machine is connected to switch : {}", destNode.toString()); - //Get path between both the nodes + // Get path between both the nodes NodeConnector forwardPort = null; - if(clientNode.getNodeIDString().equals(destNode.getNodeIDString())){ + if (clientNode.getNodeIDString().equals(destNode.getNodeIDString())) { forwardPort = hnConnector.getnodeConnector(); - lbsLogger.info("Both source (client) and destination pool machine is connected to same switch nodes. Respective ports are - {},{}",forwardPort,inPkt.getIncomingNodeConnector()); + lbsLogger + .info("Both source (client) and destination pool machine is connected to same switch nodes. Respective ports are - {},{}", + forwardPort, inPkt.getIncomingNodeConnector()); - }else{ + } else { Path route = this.routing.getRoute(clientNode, destNode); - lbsLogger.info("Path between source (client) and destination switch nodes : {}",route.toString()); + lbsLogger.info("Path between source (client) and destination switch nodes : {}", + route.toString()); forwardPort = route.getEdges().get(0).getTailNodeConnector(); } - if(installLoadBalancerFlow(client, - vip, - clientNode, - poolMemberIp, - hnConnector.getDataLayerAddressBytes(), - forwardPort, - LBConst.FORWARD_DIRECTION_LB_FLOW)){ - lbsLogger.info("Traffic from client : {} will be routed " + - "to pool machine : {}",client,poolMemberIp); - }else{ - lbsLogger.error("Not able to route traffic from client : {}",client ); + if (installLoadBalancerFlow(client, vip, clientNode, poolMemberIp, + hnConnector.getDataLayerAddressBytes(), forwardPort, + LBConst.FORWARD_DIRECTION_LB_FLOW)) { + lbsLogger.info("Traffic from client : {} will be routed " + "to pool machine : {}", + client, poolMemberIp); + } else { + lbsLogger.error("Not able to route traffic from client : {}", client); } - if(installLoadBalancerFlow(client, - vip, - clientNode, - poolMemberIp, - vipMacAddr, - inPkt.getIncomingNodeConnector(), - LBConst.REVERSE_DIRECTION_LB_FLOW)){ - lbsLogger.info("Flow rule installed to change the source ip/mac from " + - "pool machine ip {} to VIP {} for traffic coming pool machine",poolMemberIp,vip); - }else{ - lbsLogger.error("Not able to route traffic from client : {}",client ); + if (installLoadBalancerFlow(client, vip, clientNode, poolMemberIp, vipMacAddr, + inPkt.getIncomingNodeConnector(), LBConst.REVERSE_DIRECTION_LB_FLOW)) { + lbsLogger.info("Flow rule installed to change the source ip/mac from " + + "pool machine ip {} to VIP {} for traffic coming pool machine", poolMemberIp, + vip); + } else { + lbsLogger.error("Not able to route traffic from client : {}", client); } - }catch (UnknownHostException e) { - lbsLogger.error("Pool member not found in the network : {}",e.getMessage()); - lbsLogger.error("",e); + } catch (UnknownHostException e) { + lbsLogger.error("Pool member not found in the network : {}", e.getMessage()); + lbsLogger.error("", e); } } } @@ -309,30 +311,37 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ } /* - * This method installs the flow rule for routing the traffic between two hosts. - * @param source Traffic is sent by this source - * @param dest Traffic is destined to this destination (VIP) - * @param sourceSwitch Switch from where controller received the packet - * @param destMachineIp IP address of the pool member where traffic needs to be routed - * @param destMachineMac MAC address of the pool member where traffic needs to be routed - * @param outport Use this port to send out traffic - * @param flowDirection FORWARD_DIRECTION_LB_FLOW or REVERSE_DIRECTION_LB_FLOW - * @return true If flow installation was successful - * false else - * @throws UnknownHostException + * This method installs the flow rule for routing the traffic between two + * hosts. + * + * @param source Traffic is sent by this source + * + * @param dest Traffic is destined to this destination (VIP) + * + * @param sourceSwitch Switch from where controller received the packet + * + * @param destMachineIp IP address of the pool member where traffic needs to + * be routed + * + * @param destMachineMac MAC address of the pool member where traffic needs + * to be routed + * + * @param outport Use this port to send out traffic + * + * @param flowDirection FORWARD_DIRECTION_LB_FLOW or + * REVERSE_DIRECTION_LB_FLOW + * + * @return true If flow installation was successful false else + * + * @throws UnknownHostException */ - private boolean installLoadBalancerFlow(Client source, - VIP dest, - Node sourceSwitch, - String destMachineIp, - byte[] destMachineMac, - NodeConnector outport, - int flowDirection) throws UnknownHostException{ + private boolean installLoadBalancerFlow(Client source, VIP dest, Node sourceSwitch, String destMachineIp, + byte[] destMachineMac, NodeConnector outport, int flowDirection) throws UnknownHostException { Match match = new Match(); List actions = new ArrayList(); - if(flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW){ + if (flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW) { match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue()); match.setField(MatchType.NW_SRC, InetAddress.getByName(source.getIp())); match.setField(MatchType.NW_DST, InetAddress.getByName(dest.getIp())); @@ -344,13 +353,13 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ actions.add(new SetDlDst(destMachineMac)); } - if(flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW){ + if (flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW) { match.setField(MatchType.DL_TYPE, EtherTypes.IPv4.shortValue()); match.setField(MatchType.NW_SRC, InetAddress.getByName(destMachineIp)); match.setField(MatchType.NW_DST, InetAddress.getByName(source.getIp())); match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(source.getProtocol())); match.setField(MatchType.TP_SRC, dest.getPort()); - match.setField(MatchType.TP_DST,source.getPort()); + match.setField(MatchType.TP_DST, source.getPort()); actions.add(new SetNwSrc(InetAddress.getByName(dest.getIp()))); actions.add(new SetDlSrc(destMachineMac)); @@ -366,30 +375,30 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ flow.setHardTimeout((short) 0); flow.setPriority(LB_IPSWITCH_PRIORITY); - String policyName = source.getIp()+":"+source.getProtocol()+":"+source.getPort(); - String flowName =null; + String policyName = source.getIp() + ":" + source.getProtocol() + ":" + source.getPort(); + String flowName = null; - if(flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW){ - flowName = "["+policyName+":"+source.getIp() + ":"+dest.getIp()+"]"; + if (flowDirection == LBConst.FORWARD_DIRECTION_LB_FLOW) { + flowName = "[" + policyName + ":" + source.getIp() + ":" + dest.getIp() + "]"; } - if(flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW){ + if (flowDirection == LBConst.REVERSE_DIRECTION_LB_FLOW) { - flowName = "["+policyName+":"+dest.getIp() + ":"+source.getIp()+"]"; + flowName = "[" + policyName + ":" + dest.getIp() + ":" + source.getIp() + "]"; } FlowEntry fEntry = new FlowEntry(policyName, flowName, flow, sourceSwitch); - lbsLogger.info("Install flow entry {} on node {}",fEntry.toString(),sourceSwitch.toString()); + lbsLogger.info("Install flow entry {} on node {}", fEntry.toString(), sourceSwitch.toString()); - if(!this.ruleManager.checkFlowEntryConflict(fEntry)){ - if(this.ruleManager.installFlowEntry(fEntry).isSuccess()){ + if (!this.ruleManager.checkFlowEntryConflict(fEntry)) { + if (this.ruleManager.installFlowEntry(fEntry).isSuccess()) { return true; - }else{ - lbsLogger.error("Error in installing flow entry to node : {}",sourceSwitch); + } else { + lbsLogger.error("Error in installing flow entry to node : {}", sourceSwitch); } - }else{ - lbsLogger.error("Conflicting flow entry exists : {}",fEntry.toString()); + } else { + lbsLogger.error("Conflicting flow entry exists : {}", fEntry.toString()); } return false; } @@ -405,45 +414,45 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ this.containerName = (String) props.get("containerName"); lbsLogger.info("Running container name:" + this.containerName); - }else { + } else { // In the Global instance case the containerName is empty this.containerName = ""; } lbsLogger.info(configManager.toString()); + } /** - * Function called by the dependency manager when at least one - * dependency become unsatisfied or when the component is shutting - * down because for example bundle is being stopped. + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. * */ void destroy() { } /** - * Function called by dependency manager after "init ()" is called - * and after the services provided by the class are registered in - * the service registry + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry * */ void start() { } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls * */ void stop() { } /* - * All the methods below are just proxy methods to direct the REST API requests to configuration - * manager. We need this redirection as currently, opendaylight supports only one - * implementation of the service. + * All the methods below are just proxy methods to direct the REST API + * requests to configuration manager. We need this redirection as currently, + * opendaylight supports only one implementation of the service. */ @Override public Set getAllVIPs() { @@ -451,8 +460,7 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ } @Override - public boolean vipExists(String name, String ip, String protocol, - short protocolPort, String poolName) { + public boolean vipExists(String name, String ip, String protocol, short protocolPort, String poolName) { return configManager.vipExists(name, ip, protocol, protocolPort, poolName); } @@ -462,8 +470,7 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ } @Override - public VIP createVIP(String name, String ip, String protocol, - short protocolPort, String poolName) { + public VIP createVIP(String name, String ip, String protocol, short protocolPort, String poolName) { return configManager.createVIP(name, ip, protocol, protocolPort, poolName); } @@ -489,9 +496,7 @@ public class LoadBalancerService implements IListenDataPacket, IConfigManager{ } @Override - public PoolMember addPoolMember(String name, - String memberIP, - String poolName) { + public PoolMember addPoolMember(String name, String memberIP, String poolName) { return configManager.addPoolMember(name, memberIP, poolName); } diff --git a/opendaylight/samples/northbound/loadbalancer/pom.xml b/opendaylight/samples/northbound/loadbalancer/pom.xml index a3f0ba122e..543aa8ca54 100644 --- a/opendaylight/samples/northbound/loadbalancer/pom.xml +++ b/opendaylight/samples/northbound/loadbalancer/pom.xml @@ -79,12 +79,12 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller samples.loadbalancer - 0.4.1-SNAPSHOT + ${samples.loadbalancer} org.opendaylight.controller diff --git a/opendaylight/statisticsmanager/integrationtest/pom.xml b/opendaylight/statisticsmanager/integrationtest/pom.xml index c9103994a0..743c6784a5 100644 --- a/opendaylight/statisticsmanager/integrationtest/pom.xml +++ b/opendaylight/statisticsmanager/integrationtest/pom.xml @@ -91,7 +91,7 @@ org.opendaylight.controller hosttracker - 0.4.1-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/topologymanager/integrationtest/pom.xml b/opendaylight/topologymanager/integrationtest/pom.xml index 0f2138bf87..d4d3d1c857 100644 --- a/opendaylight/topologymanager/integrationtest/pom.xml +++ b/opendaylight/topologymanager/integrationtest/pom.xml @@ -91,7 +91,7 @@ org.opendaylight.controller hosttracker - 0.4.0-SNAPSHOT + ${hosttracker.version} org.opendaylight.controller diff --git a/opendaylight/web/devices/pom.xml b/opendaylight/web/devices/pom.xml index f5605eaffe..d66381f6ce 100644 --- a/opendaylight/web/devices/pom.xml +++ b/opendaylight/web/devices/pom.xml @@ -124,7 +124,7 @@ org.opendaylight.controller forwarding.staticrouting - 0.4.1-SNAPSHOT + ${forwarding.staticrouting} org.codehaus.jackson diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java index a8290ce57f..8fec9a0f54 100644 --- a/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java +++ b/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java @@ -44,1770 +44,1802 @@ import ch.ethz.ssh2.transport.TransportManager; */ public class ChannelManager implements MessageHandler { - private static final Logger log = Logger.getLogger(ChannelManager.class); - - private final ServerConnectionState server_state; - private final TransportManager tm; - - private final HashMap x11_magic_cookies = new HashMap(); - - private final List channels = new Vector(); - private int nextLocalChannel = 100; - private boolean shutdown = false; - private int globalSuccessCounter = 0; - private int globalFailedCounter = 0; - - private final HashMap remoteForwardings = new HashMap(); - - private final List listenerThreads = new Vector(); - - private boolean listenerThreadsAllowed = true; - - /** - * Constructor for client-mode. - * @param tm - */ - public ChannelManager(TransportManager tm) - { - this.server_state = null; - this.tm = tm; - tm.registerMessageHandler(this, 80, 100); - } - - /** - * Constructor for server-mode. - * @param state - */ - public ChannelManager(ServerConnectionState state) - { - this.server_state = state; - this.tm = state.tm; - tm.registerMessageHandler(this, 80, 100); - } - - private Channel getChannel(int id) - { - synchronized (channels) - { - for (Channel c : channels) - { - if (c.localID == id) - return c; - } - } - return null; - } - - private void removeChannel(int id) - { - synchronized (channels) - { - for (Channel c : channels) - { - if (c.localID == id) - { - channels.remove(c); - break; - } - } - } - } - - private int addChannel(Channel c) - { - synchronized (channels) - { - channels.add(c); - return nextLocalChannel++; - } - } - - private void waitUntilChannelOpen(Channel c) throws IOException - { - boolean wasInterrupted = false; - - synchronized (c) - { - while (c.state == Channel.STATE_OPENING) - { - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - wasInterrupted = true; - } - } - - if (c.state != Channel.STATE_OPEN) - { - removeChannel(c.localID); - - String detail = c.getReasonClosed(); - - if (detail == null) - detail = "state: " + c.state; - - throw new IOException("Could not open channel (" + detail + ")"); - } - } - - if (wasInterrupted) - Thread.currentThread().interrupt(); - } - - private void waitForGlobalSuccessOrFailure() throws IOException - { - boolean wasInterrupted = false; - - try - { - synchronized (channels) - { - while ((globalSuccessCounter == 0) && (globalFailedCounter == 0)) - { - if (shutdown) - { - throw new IOException("The connection is being shutdown"); - } - - try - { - channels.wait(); - } - catch (InterruptedException ignore) - { - wasInterrupted = true; - } - } - - if (globalFailedCounter != 0) - { - throw new IOException("The server denied the request (did you enable port forwarding?)"); - } - - if (globalSuccessCounter == 0) - { - throw new IOException("Illegal state."); - } - } - } - finally - { - if (wasInterrupted) - Thread.currentThread().interrupt(); - } - } - - private void waitForChannelSuccessOrFailure(Channel c) throws IOException - { - boolean wasInterrupted = false; - - try - { - synchronized (c) - { - while ((c.successCounter == 0) && (c.failedCounter == 0)) - { - if (c.state != Channel.STATE_OPEN) - { - String detail = c.getReasonClosed(); - - if (detail == null) - detail = "state: " + c.state; - - throw new IOException("This SSH2 channel is not open (" + detail + ")"); - } - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - wasInterrupted = true; - } - } - - if (c.failedCounter != 0) - { - throw new IOException("The server denied the request."); - } - } - } - finally - { - if (wasInterrupted) - Thread.currentThread().interrupt(); - } - } - - public void registerX11Cookie(String hexFakeCookie, X11ServerData data) - { - synchronized (x11_magic_cookies) - { - x11_magic_cookies.put(hexFakeCookie, data); - } - } - - public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) - { - if (hexFakeCookie == null) - throw new IllegalStateException("hexFakeCookie may not be null"); - - synchronized (x11_magic_cookies) - { - x11_magic_cookies.remove(hexFakeCookie); - } - - if (killChannels == false) - return; - - log.debug("Closing all X11 channels for the given fake cookie"); - - List channel_copy = new Vector(); - - synchronized (channels) - { - channel_copy.addAll(channels); - } - - for (Channel c : channel_copy) - { - synchronized (c) - { - if (hexFakeCookie.equals(c.hexX11FakeCookie) == false) - continue; - } - - try - { - closeChannel(c, "Closing X11 channel since the corresponding session is closing", true); - } - catch (IOException ignored) - { - } - } - } - - public X11ServerData checkX11Cookie(String hexFakeCookie) - { - synchronized (x11_magic_cookies) - { - if (hexFakeCookie != null) - return x11_magic_cookies.get(hexFakeCookie); - } - return null; - } - - public void closeAllChannels() - { - log.debug("Closing all channels"); - - List channel_copy = new Vector(); - - synchronized (channels) - { - channel_copy.addAll(channels); - } - - for (Channel c : channel_copy) - { - try - { - closeChannel(c, "Closing all channels", true); - } - catch (IOException ignored) - { - } - } - } - - public void closeChannel(Channel c, String reason, boolean force) throws IOException - { - byte msg[] = new byte[5]; - - synchronized (c) - { - if (force) - { - c.state = Channel.STATE_CLOSED; - c.EOF = true; - } - - c.setReasonClosed(reason); - - msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - - c.notifyAll(); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(msg); - c.closeMessageSent = true; - } - - log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); - } - - public void sendEOF(Channel c) throws IOException - { - byte[] msg = new byte[5]; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - return; - - msg[0] = Packets.SSH_MSG_CHANNEL_EOF; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(msg); - } - - - log.debug("Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")"); - } - - public void sendOpenConfirmation(Channel c) throws IOException - { - PacketChannelOpenConfirmation pcoc = null; - - synchronized (c) - { - if (c.state != Channel.STATE_OPENING) - return; - - c.state = Channel.STATE_OPEN; - - pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(pcoc.getPayload()); - } - } - - public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException - { - boolean wasInterrupted = false; - - try - { - while (len > 0) - { - int thislen = 0; - byte[] msg; - - synchronized (c) - { - while (true) - { - if (c.state == Channel.STATE_CLOSED) - throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")"); - - if (c.state != Channel.STATE_OPEN) - throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")"); - - if (c.remoteWindow != 0) - break; - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - wasInterrupted = true; - } - } - - /* len > 0, no sign extension can happen when comparing */ - - thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; - - int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); - - /* The worst case scenario =) a true bottleneck */ - - if (estimatedMaxDataLen <= 0) - { - estimatedMaxDataLen = 1; - } - - if (thislen > estimatedMaxDataLen) - thislen = estimatedMaxDataLen; - - c.remoteWindow -= thislen; - - msg = new byte[1 + 8 + thislen]; - - msg[0] = Packets.SSH_MSG_CHANNEL_DATA; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - msg[5] = (byte) (thislen >> 24); - msg[6] = (byte) (thislen >> 16); - msg[7] = (byte) (thislen >> 8); - msg[8] = (byte) (thislen); - - System.arraycopy(buffer, pos, msg, 9, thislen); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")"); - - tm.sendMessage(msg); - } - - pos += thislen; - len -= thislen; - } - } - finally - { - if (wasInterrupted) - Thread.currentThread().interrupt(); - } - } - - public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort) - throws IOException - { - RemoteForwardingData rfd = new RemoteForwardingData(); - - rfd.bindAddress = bindAddress; - rfd.bindPort = bindPort; - rfd.targetAddress = targetAddress; - rfd.targetPort = targetPort; - - synchronized (remoteForwardings) - { - Integer key = new Integer(bindPort); - - if (remoteForwardings.get(key) != null) - { - throw new IOException("There is already a forwarding for remote port " + bindPort); - } - - remoteForwardings.put(key, rfd); - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort); - tm.sendMessage(pgf.getPayload()); - - log.debug("Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")"); - - try - { - waitForGlobalSuccessOrFailure(); - } - catch (IOException e) - { - synchronized (remoteForwardings) - { - remoteForwardings.remove(rfd); - } - throw e; - } - - return bindPort; - } + private static final Logger log = Logger.getLogger(ChannelManager.class); + + private final ServerConnectionState server_state; + private final TransportManager tm; + + private final HashMap x11_magic_cookies = new HashMap(); + + private final List channels = new Vector(); + private int nextLocalChannel = 100; + private boolean shutdown = false; + private int globalSuccessCounter = 0; + private int globalFailedCounter = 0; + + private final HashMap remoteForwardings = new HashMap(); + + private final List listenerThreads = new Vector(); + + private boolean listenerThreadsAllowed = true; + + /** + * Constructor for client-mode. + * @param tm + */ + public ChannelManager(TransportManager tm) + { + this.server_state = null; + this.tm = tm; + tm.registerMessageHandler(this, 80, 100); + } + + /** + * Constructor for server-mode. + * @param state + */ + public ChannelManager(ServerConnectionState state) + { + this.server_state = state; + this.tm = state.tm; + tm.registerMessageHandler(this, 80, 100); + } + + private Channel getChannel(int id) + { + synchronized (channels) + { + for (Channel c : channels) + { + if (c.localID == id) + return c; + } + } + return null; + } + + private void removeChannel(int id) + { + synchronized (channels) + { + for (Channel c : channels) + { + if (c.localID == id) + { + channels.remove(c); + break; + } + } + } + } + + private int addChannel(Channel c) + { + synchronized (channels) + { + channels.add(c); + return nextLocalChannel++; + } + } + + private void waitUntilChannelOpen(Channel c) throws IOException + { + boolean wasInterrupted = false; + + synchronized (c) + { + while (c.state == Channel.STATE_OPENING) + { + try + { + c.wait(); + } + catch (InterruptedException ignore) + { + wasInterrupted = true; + } + } + + if (c.state != Channel.STATE_OPEN) + { + removeChannel(c.localID); + + String detail = c.getReasonClosed(); + + if (detail == null) + detail = "state: " + c.state; + + throw new IOException("Could not open channel (" + detail + ")"); + } + } + + if (wasInterrupted) + Thread.currentThread().interrupt(); + } + + private void waitForGlobalSuccessOrFailure() throws IOException + { + boolean wasInterrupted = false; + + try + { + synchronized (channels) + { + while ((globalSuccessCounter == 0) && (globalFailedCounter == 0)) + { + if (shutdown) + { + throw new IOException("The connection is being shutdown"); + } + + try + { + channels.wait(); + } + catch (InterruptedException ignore) + { + wasInterrupted = true; + } + } + + if (globalFailedCounter != 0) + { + throw new IOException("The server denied the request (did you enable port forwarding?)"); + } + + if (globalSuccessCounter == 0) + { + throw new IOException("Illegal state."); + } + } + } + finally + { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } + } + + private void waitForChannelSuccessOrFailure(Channel c) throws IOException + { + boolean wasInterrupted = false; + + try + { + synchronized (c) + { + while ((c.successCounter == 0) && (c.failedCounter == 0)) + { + if (c.state != Channel.STATE_OPEN) + { + String detail = c.getReasonClosed(); + + if (detail == null) + detail = "state: " + c.state; + + throw new IOException("This SSH2 channel is not open (" + detail + ")"); + } + + try + { + c.wait(); + } + catch (InterruptedException ignore) + { + wasInterrupted = true; + } + } + + if (c.failedCounter != 0) + { + throw new IOException("The server denied the request."); + } + } + } + finally + { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } + } + + public void registerX11Cookie(String hexFakeCookie, X11ServerData data) + { + synchronized (x11_magic_cookies) + { + x11_magic_cookies.put(hexFakeCookie, data); + } + } + + public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) + { + if (hexFakeCookie == null) + throw new IllegalStateException("hexFakeCookie may not be null"); + + synchronized (x11_magic_cookies) + { + x11_magic_cookies.remove(hexFakeCookie); + } + + if (killChannels == false) + return; + + log.debug("Closing all X11 channels for the given fake cookie"); + + List channel_copy = new Vector(); + + synchronized (channels) + { + channel_copy.addAll(channels); + } + + for (Channel c : channel_copy) + { + synchronized (c) + { + if (hexFakeCookie.equals(c.hexX11FakeCookie) == false) + continue; + } + + try + { + closeChannel(c, "Closing X11 channel since the corresponding session is closing", true); + } + catch (IOException ignored) + { + } + } + } + + public X11ServerData checkX11Cookie(String hexFakeCookie) + { + synchronized (x11_magic_cookies) + { + if (hexFakeCookie != null) + return x11_magic_cookies.get(hexFakeCookie); + } + return null; + } + + public void closeAllChannels() + { + log.debug("Closing all channels"); + + List channel_copy = new Vector(); + + synchronized (channels) + { + channel_copy.addAll(channels); + } + + for (Channel c : channel_copy) + { + try + { + closeChannel(c, "Closing all channels", true); + } + catch (IOException ignored) + { + } + } + } + + public void closeChannel(Channel c, String reason, boolean force) throws IOException + { + byte msg[] = new byte[5]; + + synchronized (c) + { + if (force) + { + c.state = Channel.STATE_CLOSED; + c.EOF = true; + } + + c.setReasonClosed(reason); + + msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; + msg[1] = (byte) (c.remoteID >> 24); + msg[2] = (byte) (c.remoteID >> 16); + msg[3] = (byte) (c.remoteID >> 8); + msg[4] = (byte) (c.remoteID); + + c.notifyAll(); + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent == true) + return; + tm.sendMessage(msg); + c.closeMessageSent = true; + } + + log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); + } + + public void sendEOF(Channel c) throws IOException + { + byte[] msg = new byte[5]; + + synchronized (c) + { + if (c.state != Channel.STATE_OPEN) + return; + + msg[0] = Packets.SSH_MSG_CHANNEL_EOF; + msg[1] = (byte) (c.remoteID >> 24); + msg[2] = (byte) (c.remoteID >> 16); + msg[3] = (byte) (c.remoteID >> 8); + msg[4] = (byte) (c.remoteID); + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent == true) + return; + tm.sendMessage(msg); + } + + + log.debug("Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")"); + } + + public void sendOpenConfirmation(Channel c) throws IOException + { + PacketChannelOpenConfirmation pcoc = null; + + synchronized (c) + { + if (c.state != Channel.STATE_OPENING) + return; + + c.state = Channel.STATE_OPEN; + + pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent == true) + return; + tm.sendMessage(pcoc.getPayload()); + } + } + + public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException + { + boolean wasInterrupted = false; + + try + { + while (len > 0) + { + int thislen = 0; + byte[] msg; + + synchronized (c) + { + while (true) + { + if (c.state == Channel.STATE_CLOSED) + throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")"); + + if (c.state != Channel.STATE_OPEN) + throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")"); + + if (c.remoteWindow != 0) + break; + + try + { + c.wait(); + } + catch (InterruptedException ignore) + { + wasInterrupted = true; + } + } + + /* len > 0, no sign extension can happen when comparing */ + + thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; + + int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); + + /* The worst case scenario =) a true bottleneck */ + + if (estimatedMaxDataLen <= 0) + { + estimatedMaxDataLen = 1; + } + + if (thislen > estimatedMaxDataLen) + thislen = estimatedMaxDataLen; + + c.remoteWindow -= thislen; + + msg = new byte[1 + 8 + thislen]; + + msg[0] = Packets.SSH_MSG_CHANNEL_DATA; + msg[1] = (byte) (c.remoteID >> 24); + msg[2] = (byte) (c.remoteID >> 16); + msg[3] = (byte) (c.remoteID >> 8); + msg[4] = (byte) (c.remoteID); + msg[5] = (byte) (thislen >> 24); + msg[6] = (byte) (thislen >> 16); + msg[7] = (byte) (thislen >> 8); + msg[8] = (byte) (thislen); + + System.arraycopy(buffer, pos, msg, 9, thislen); + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent == true) + throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")"); + + tm.sendMessage(msg); + } + + pos += thislen; + len -= thislen; + } + } + finally + { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } + } + + public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort) + throws IOException + { + RemoteForwardingData rfd = new RemoteForwardingData(); + + rfd.bindAddress = bindAddress; + rfd.bindPort = bindPort; + rfd.targetAddress = targetAddress; + rfd.targetPort = targetPort; + + synchronized (remoteForwardings) + { + Integer key = new Integer(bindPort); + + if (remoteForwardings.get(key) != null) + { + throw new IOException("There is already a forwarding for remote port " + bindPort); + } + + remoteForwardings.put(key, rfd); + } + + synchronized (channels) + { + globalSuccessCounter = globalFailedCounter = 0; + } + + PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort); + tm.sendMessage(pgf.getPayload()); + + log.debug("Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")"); + + try + { + waitForGlobalSuccessOrFailure(); + } + catch (IOException e) + { + synchronized (remoteForwardings) + { + remoteForwardings.remove(rfd); + } + throw e; + } + + return bindPort; + } - public void requestCancelGlobalForward(int bindPort) throws IOException - { - RemoteForwardingData rfd = null; - - synchronized (remoteForwardings) - { - rfd = remoteForwardings.get(new Integer(bindPort)); - - if (rfd == null) - throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort); - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress, - rfd.bindPort); - tm.sendMessage(pgcf.getPayload()); - - log.debug("Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")"); - - waitForGlobalSuccessOrFailure(); - - /* Only now we are sure that no more forwarded connections will arrive */ - - synchronized (remoteForwardings) - { - remoteForwardings.remove(rfd); - } - } - - public void registerThread(IChannelWorkerThread thr) throws IOException - { - synchronized (listenerThreads) - { - if (listenerThreadsAllowed == false) - throw new IOException("Too late, this connection is closed."); - listenerThreads.add(thr); - } - } - - public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address, - int originator_port) throws IOException - { - Channel c = new Channel(this); - - synchronized (c) - { - c.localID = addChannel(c); - // end of synchronized block forces writing out to main memory - } - - PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow, - c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port); - - tm.sendMessage(dtc.getPayload()); - - waitUntilChannelOpen(c); - - return c; - } - - public Channel openSessionChannel() throws IOException - { - Channel c = new Channel(this); - - synchronized (c) - { - c.localID = addChannel(c); - // end of synchronized block forces the writing out to main memory - } - - log.debug("Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")"); - - PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize); - tm.sendMessage(smo.getPayload()); - - waitUntilChannelOpen(c); - - return c; - } - - public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters, - int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException - { - PacketSessionPtyRequest spr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); - - spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters, - term_width_pixels, term_height_pixels, terminal_modes); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(spr.getPayload()); - } - - try - { - waitForChannelSuccessOrFailure(c); - } - catch (IOException e) - { - throw (IOException) new IOException("PTY request failed").initCause(e); - } - } - - public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol, - String x11AuthenticationCookie, int x11ScreenNumber) throws IOException - { - PacketSessionX11Request psr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); - - psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol, - x11AuthenticationCookie, x11ScreenNumber); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(psr.getPayload()); - } - - log.debug("Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")"); - - try - { - waitForChannelSuccessOrFailure(c); - } - catch (IOException e) - { - throw (IOException) new IOException("The X11 request failed.").initCause(e); - } - } - - public void requestSubSystem(Channel c, String subSystemName) throws IOException - { - PacketSessionSubsystemRequest ssr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); - - ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(ssr.getPayload()); - } - - try - { - waitForChannelSuccessOrFailure(c); - } - catch (IOException e) - { - throw (IOException) new IOException("The subsystem request failed.").initCause(e); - } - } - - public void requestExecCommand(Channel c, String cmd) throws IOException - { - this.requestExecCommand(c, cmd, null); - } - - /** - * @param charsetName The charset used to convert between Java Unicode Strings and byte encodings - */ - public void requestExecCommand(Channel c, String cmd, String charsetName) throws IOException - { - PacketSessionExecCommand sm; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); - - sm = new PacketSessionExecCommand(c.remoteID, true, cmd); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(sm.getPayload(charsetName)); - } - - log.debug("Executing command (channel " + c.localID + ", '" + cmd + "')"); - - try - { - waitForChannelSuccessOrFailure(c); - } - catch (IOException e) - { - throw (IOException) new IOException("The execute request failed.").initCause(e); - } - } - - public void requestShell(Channel c) throws IOException - { - PacketSessionStartShell sm; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); - - sm = new PacketSessionStartShell(c.remoteID, true); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(sm.getPayload()); - } - - try - { - waitForChannelSuccessOrFailure(c); - } - catch (IOException e) - { - throw (IOException) new IOException("The shell request failed.").initCause(e); - } - } - - public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException - { - if (msglen <= 13) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id); - - if (dataType != Packets.SSH_EXTENDED_DATA_STDERR) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")"); - - if (len != (msglen - 13)) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13) - + ", got " + len + ")"); - - log.debug("Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")"); - - synchronized (c) - { - if (c.state == Channel.STATE_CLOSED) - return; // ignore - - if (c.state != Channel.STATE_OPEN) - throw new IOException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (" - + c.state + ")"); - - if (c.localWindow < len) - throw new IOException("Remote sent too much data, does not fit into window."); - - c.localWindow -= len; - - System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len); - c.stderrWritepos += len; - - c.notifyAll(); - } - } - - /** - * Wait until for a condition. - * - * @param c Channel - * @param timeout in ms, 0 means no timeout. - * @param condition_mask minimum event mask (at least one of the conditions must be fulfilled) - * @return all current events - */ - public int waitForCondition(Channel c, long timeout, int condition_mask) - { - boolean wasInterrupted = false; - - try - { - long end_time = 0; - boolean end_time_set = false; - - synchronized (c) - { - while (true) - { - int current_cond = 0; - - int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; - int stderrAvail = c.stderrWritepos - c.stderrReadpos; - - if (stdoutAvail > 0) - current_cond = current_cond | ChannelCondition.STDOUT_DATA; - - if (stderrAvail > 0) - current_cond = current_cond | ChannelCondition.STDERR_DATA; - - if (c.EOF) - current_cond = current_cond | ChannelCondition.EOF; - - if (c.getExitStatus() != null) - current_cond = current_cond | ChannelCondition.EXIT_STATUS; - - if (c.getExitSignal() != null) - current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; - - if (c.state == Channel.STATE_CLOSED) - return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; - - if ((current_cond & condition_mask) != 0) - return current_cond; - - if (timeout > 0) - { - if (!end_time_set) - { - end_time = System.currentTimeMillis() + timeout; - end_time_set = true; - } - else - { - timeout = end_time - System.currentTimeMillis(); - - if (timeout <= 0) - return current_cond | ChannelCondition.TIMEOUT; - } - } - - try - { - if (timeout > 0) - c.wait(timeout); - else - c.wait(); - } - catch (InterruptedException e) - { - wasInterrupted = true; - } - } - } - } - finally - { - if (wasInterrupted) - Thread.currentThread().interrupt(); - } - } - - public int getAvailable(Channel c, boolean extended) throws IOException - { - synchronized (c) - { - int avail; - - if (extended) - avail = c.stderrWritepos - c.stderrReadpos; - else - avail = c.stdoutWritepos - c.stdoutReadpos; - - return ((avail > 0) ? avail : (c.EOF ? -1 : 0)); - } - } - - public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException - { - boolean wasInterrupted = false; - - try - { - int copylen = 0; - int increment = 0; - int remoteID = 0; - int localID = 0; - - synchronized (c) - { - int stdoutAvail = 0; - int stderrAvail = 0; - - while (true) - { - /* - * Data available? We have to return remaining data even if the - * channel is already closed. - */ - - stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; - stderrAvail = c.stderrWritepos - c.stderrReadpos; - - if ((!extended) && (stdoutAvail != 0)) - break; - - if ((extended) && (stderrAvail != 0)) - break; - - /* Do not wait if more data will never arrive (EOF or CLOSED) */ - - if ((c.EOF) || (c.state != Channel.STATE_OPEN)) - return -1; - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - wasInterrupted = true; - } - } - - /* OK, there is some data. Return it. */ - - if (!extended) - { - copylen = (stdoutAvail > len) ? len : stdoutAvail; - System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); - c.stdoutReadpos += copylen; - - if (c.stdoutReadpos != c.stdoutWritepos) - - System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos - - c.stdoutReadpos); - - c.stdoutWritepos -= c.stdoutReadpos; - c.stdoutReadpos = 0; - } - else - { - copylen = (stderrAvail > len) ? len : stderrAvail; - System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); - c.stderrReadpos += copylen; - - if (c.stderrReadpos != c.stderrWritepos) - - System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos - - c.stderrReadpos); - - c.stderrWritepos -= c.stderrReadpos; - c.stderrReadpos = 0; - } - - if (c.state != Channel.STATE_OPEN) - return copylen; - - if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) - { - int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, - Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos); - - increment = minFreeSpace - c.localWindow; - c.localWindow = minFreeSpace; - } - - remoteID = c.remoteID; /* read while holding the lock */ - localID = c.localID; /* read while holding the lock */ - } + public void requestCancelGlobalForward(int bindPort) throws IOException + { + RemoteForwardingData rfd = null; + + synchronized (remoteForwardings) + { + rfd = remoteForwardings.get(new Integer(bindPort)); + + if (rfd == null) + throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort); + } + + synchronized (channels) + { + globalSuccessCounter = globalFailedCounter = 0; + } + + PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress, + rfd.bindPort); + tm.sendMessage(pgcf.getPayload()); + + log.debug("Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")"); + + waitForGlobalSuccessOrFailure(); + + /* Only now we are sure that no more forwarded connections will arrive */ + + synchronized (remoteForwardings) + { + remoteForwardings.remove(rfd); + } + } + + public void registerThread(IChannelWorkerThread thr) throws IOException + { + synchronized (listenerThreads) + { + if (listenerThreadsAllowed == false) + throw new IOException("Too late, this connection is closed."); + listenerThreads.add(thr); + } + } + + public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address, + int originator_port) throws IOException + { + Channel c = new Channel(this); + + synchronized (c) + { + c.localID = addChannel(c); + // end of synchronized block forces writing out to main memory + } + + PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow, + c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port); + + tm.sendMessage(dtc.getPayload()); + + waitUntilChannelOpen(c); + + return c; + } + + public Channel openSessionChannel() throws IOException + { + Channel c = new Channel(this); + + synchronized (c) + { + c.localID = addChannel(c); + // end of synchronized block forces the writing out to main memory + } + + log.debug("Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")"); + + PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize); + tm.sendMessage(smo.getPayload()); + + waitUntilChannelOpen(c); + + return c; + } + + public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters, + int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException + { + PacketSessionPtyRequest spr; + + synchronized (c) + { + if (c.state != Channel.STATE_OPEN) + throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); + + spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters, + term_width_pixels, term_height_pixels, terminal_modes); + + c.successCounter = c.failedCounter = 0; + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent) + throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); + tm.sendMessage(spr.getPayload()); + } + + try + { + waitForChannelSuccessOrFailure(c); + } + catch (IOException e) + { + throw (IOException) new IOException("PTY request failed").initCause(e); + } + } + + public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol, + String x11AuthenticationCookie, int x11ScreenNumber) throws IOException + { + PacketSessionX11Request psr; + + synchronized (c) + { + if (c.state != Channel.STATE_OPEN) + throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); + + psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol, + x11AuthenticationCookie, x11ScreenNumber); + + c.successCounter = c.failedCounter = 0; + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent) + throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); + tm.sendMessage(psr.getPayload()); + } + + log.debug("Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")"); + + try + { + waitForChannelSuccessOrFailure(c); + } + catch (IOException e) + { + throw (IOException) new IOException("The X11 request failed.").initCause(e); + } + } + + public void requestSubSystem(Channel c, String subSystemName) throws IOException + { + PacketSessionSubsystemRequest ssr; + + synchronized (c) + { + if (c.state != Channel.STATE_OPEN) + throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); + + ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName); + + c.successCounter = c.failedCounter = 0; + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent) + throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); + tm.sendMessage(ssr.getPayload()); + } + + try + { + waitForChannelSuccessOrFailure(c); + } + catch (IOException e) + { + throw (IOException) new IOException("The subsystem request failed.").initCause(e); + } + } + + public void requestExecCommand(Channel c, String cmd) throws IOException + { + this.requestExecCommand(c, cmd, null); + } + + /** + * @param charsetName The charset used to convert between Java Unicode Strings and byte encodings + */ + public void requestExecCommand(Channel c, String cmd, String charsetName) throws IOException + { + PacketSessionExecCommand sm; + + synchronized (c) + { + if (c.state != Channel.STATE_OPEN) + throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); + + sm = new PacketSessionExecCommand(c.remoteID, true, cmd); + + c.successCounter = c.failedCounter = 0; + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent) + throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); + tm.sendMessage(sm.getPayload(charsetName)); + } + + log.debug("Executing command (channel " + c.localID + ", '" + cmd + "')"); + + try + { + waitForChannelSuccessOrFailure(c); + } + catch (IOException e) + { + throw (IOException) new IOException("The execute request failed.").initCause(e); + } + } + + public void requestShell(Channel c) throws IOException + { + PacketSessionStartShell sm; + + synchronized (c) + { + if (c.state != Channel.STATE_OPEN) + throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); + + sm = new PacketSessionStartShell(c.remoteID, true); + + c.successCounter = c.failedCounter = 0; + } + + synchronized (c.channelSendLock) + { + if (c.closeMessageSent) + throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); + tm.sendMessage(sm.getPayload()); + } + + try + { + waitForChannelSuccessOrFailure(c); + } + catch (IOException e) + { + throw (IOException) new IOException("The shell request failed.").initCause(e); + } + } + + public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException + { + if (msglen <= 13) + throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")"); + + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); + int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff); + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id); + + if (dataType != Packets.SSH_EXTENDED_DATA_STDERR) + throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")"); + + if (len != (msglen - 13)) + throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13) + + ", got " + len + ")"); + + log.debug("Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")"); + + synchronized (c) + { + if (c.state == Channel.STATE_CLOSED) + return; // ignore + + if (c.state != Channel.STATE_OPEN) + throw new IOException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (" + + c.state + ")"); + + if (c.localWindow < len) + throw new IOException("Remote sent too much data, does not fit into window."); + + c.localWindow -= len; + + System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len); + c.stderrWritepos += len; + + c.notifyAll(); + } + } + + /** + * Wait until for a condition. + * + * @param c Channel + * @param timeout in ms, 0 means no timeout. + * @param condition_mask minimum event mask (at least one of the conditions must be fulfilled) + * @return all current events + */ + public int waitForCondition(Channel c, long timeout, int condition_mask) + { + boolean wasInterrupted = false; + + try + { + long end_time = 0; + boolean end_time_set = false; + + synchronized (c) + { + while (true) + { + int current_cond = 0; + + int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; + int stderrAvail = c.stderrWritepos - c.stderrReadpos; + + if (stdoutAvail > 0) + current_cond = current_cond | ChannelCondition.STDOUT_DATA; + + if (stderrAvail > 0) + current_cond = current_cond | ChannelCondition.STDERR_DATA; + + if (c.EOF) + current_cond = current_cond | ChannelCondition.EOF; + + if (c.getExitStatus() != null) + current_cond = current_cond | ChannelCondition.EXIT_STATUS; + + if (c.getExitSignal() != null) + current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; + + if (c.state == Channel.STATE_CLOSED) + return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; + + if ((current_cond & condition_mask) != 0) + return current_cond; + + if (timeout > 0) + { + if (!end_time_set) + { + end_time = System.currentTimeMillis() + timeout; + end_time_set = true; + } + else + { + timeout = end_time - System.currentTimeMillis(); + + if (timeout <= 0) + return current_cond | ChannelCondition.TIMEOUT; + } + } + + try + { + if (timeout > 0) + c.wait(timeout); + else + c.wait(); + } + catch (InterruptedException e) + { + wasInterrupted = true; + } + } + } + } + finally + { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } + } + + public int getAvailable(Channel c, boolean extended) throws IOException + { + synchronized (c) + { + int avail; + + if (extended) + avail = c.stderrWritepos - c.stderrReadpos; + else + avail = c.stdoutWritepos - c.stdoutReadpos; + + return ((avail > 0) ? avail : (c.EOF ? -1 : 0)); + } + } + + public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException + { + boolean wasInterrupted = false; + + try + { + int copylen = 0; + int increment = 0; + int remoteID = 0; + int localID = 0; + + synchronized (c) + { + int stdoutAvail = 0; + int stderrAvail = 0; + + while (true) + { + /* + * Data available? We have to return remaining data even if the + * channel is already closed. + */ + + stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; + stderrAvail = c.stderrWritepos - c.stderrReadpos; + + if ((!extended) && (stdoutAvail != 0)) + break; + + if ((extended) && (stderrAvail != 0)) + break; + + /* Do not wait if more data will never arrive (EOF or CLOSED) */ + + if ((c.EOF) || (c.state != Channel.STATE_OPEN)) + return -1; + + try + { + c.wait(); + } + catch (InterruptedException ignore) + { + wasInterrupted = true; + } + } + + /* OK, there is some data. Return it. */ + + if (!extended) + { + copylen = (stdoutAvail > len) ? len : stdoutAvail; + System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); + c.stdoutReadpos += copylen; + + if (c.stdoutReadpos != c.stdoutWritepos) + + System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos + - c.stdoutReadpos); + + c.stdoutWritepos -= c.stdoutReadpos; + c.stdoutReadpos = 0; + } + else + { + copylen = (stderrAvail > len) ? len : stderrAvail; + System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); + c.stderrReadpos += copylen; + + if (c.stderrReadpos != c.stderrWritepos) + + System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos + - c.stderrReadpos); + + c.stderrWritepos -= c.stderrReadpos; + c.stderrReadpos = 0; + } + + if (c.state != Channel.STATE_OPEN) + return copylen; + + if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) + { + int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, + Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos); + + increment = minFreeSpace - c.localWindow; + c.localWindow = minFreeSpace; + } + + remoteID = c.remoteID; /* read while holding the lock */ + localID = c.localID; /* read while holding the lock */ + } - /* - * If a consumer reads stdout and stdin in parallel, we may end up with - * sending two msgWindowAdjust messages. Luckily, it - * does not matter in which order they arrive at the server. - */ + /* + * If a consumer reads stdout and stdin in parallel, we may end up with + * sending two msgWindowAdjust messages. Luckily, it + * does not matter in which order they arrive at the server. + */ - if (increment > 0) - { - log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); + if (increment > 0) + { + log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); - synchronized (c.channelSendLock) - { - byte[] msg = c.msgWindowAdjust; + synchronized (c.channelSendLock) + { + byte[] msg = c.msgWindowAdjust; - msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; - msg[1] = (byte) (remoteID >> 24); - msg[2] = (byte) (remoteID >> 16); - msg[3] = (byte) (remoteID >> 8); - msg[4] = (byte) (remoteID); - msg[5] = (byte) (increment >> 24); - msg[6] = (byte) (increment >> 16); - msg[7] = (byte) (increment >> 8); - msg[8] = (byte) (increment); + msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; + msg[1] = (byte) (remoteID >> 24); + msg[2] = (byte) (remoteID >> 16); + msg[3] = (byte) (remoteID >> 8); + msg[4] = (byte) (remoteID); + msg[5] = (byte) (increment >> 24); + msg[6] = (byte) (increment >> 16); + msg[7] = (byte) (increment >> 8); + msg[8] = (byte) (increment); - if (c.closeMessageSent == false) - tm.sendMessage(msg); - } - } + if (c.closeMessageSent == false) + tm.sendMessage(msg); + } + } - return copylen; - } - finally - { - if (wasInterrupted) - Thread.currentThread().interrupt(); - } + return copylen; + } + finally + { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } - } + } - public void msgChannelData(byte[] msg, int msglen) throws IOException - { - if (msglen <= 9) - throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")"); + public void msgChannelData(byte[] msg, int msglen) throws IOException + { + if (msglen <= 9) + throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")"); - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - Channel c = getChannel(id); + Channel c = getChannel(id); - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); - if (len != (msglen - 9)) - throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got " - + len + ")"); + if (len != (msglen - 9)) + throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got " + + len + ")"); - log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); + log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); - synchronized (c) - { - if (c.state == Channel.STATE_CLOSED) - return; // ignore + synchronized (c) + { + if (c.state == Channel.STATE_CLOSED) + return; // ignore - if (c.state != Channel.STATE_OPEN) - throw new IOException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); + if (c.state != Channel.STATE_OPEN) + throw new IOException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); - if (c.localWindow < len) - throw new IOException("Remote sent too much data, does not fit into window."); + if (c.localWindow < len) + throw new IOException("Remote sent too much data, does not fit into window."); - c.localWindow -= len; + c.localWindow -= len; - System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); - c.stdoutWritepos += len; + System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); + c.stdoutWritepos += len; - c.notifyAll(); - } - } + c.notifyAll(); + } + } - public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException - { - if (msglen != 9) - throw new IOException("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")"); + public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException + { + if (msglen != 9) + throw new IOException("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")"); - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - Channel c = getChannel(id); + Channel c = getChannel(id); - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); - synchronized (c) - { - final long huge = 0xFFFFffffL; /* 2^32 - 1 */ + synchronized (c) + { + final long huge = 0xFFFFffffL; /* 2^32 - 1 */ - c.remoteWindow += (windowChange & huge); /* avoid sign extension */ + c.remoteWindow += (windowChange & huge); /* avoid sign extension */ - /* TODO - is this a good heuristic? */ + /* TODO - is this a good heuristic? */ - if ((c.remoteWindow > huge)) - c.remoteWindow = huge; + if ((c.remoteWindow > huge)) + c.remoteWindow = huge; - c.notifyAll(); - } + c.notifyAll(); + } - log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); - } + log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); + } - public void msgChannelOpen(byte[] msg, int msglen) throws IOException - { - TypesReader tr = new TypesReader(msg, 0, msglen); + public void msgChannelOpen(byte[] msg, int msglen) throws IOException + { + TypesReader tr = new TypesReader(msg, 0, msglen); - tr.readByte(); // skip packet type - String channelType = tr.readString(); - int remoteID = tr.readUINT32(); /* sender channel */ - int remoteWindow = tr.readUINT32(); /* initial window size */ - int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ + tr.readByte(); // skip packet type + String channelType = tr.readString(); + int remoteID = tr.readUINT32(); /* sender channel */ + int remoteWindow = tr.readUINT32(); /* initial window size */ + int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ - if ("x11".equals(channelType)) - { - synchronized (x11_magic_cookies) - { - /* If we did not request X11 forwarding, then simply ignore this bogus request. */ + if ("x11".equals(channelType)) + { + synchronized (x11_magic_cookies) + { + /* If we did not request X11 forwarding, then simply ignore this bogus request. */ - if (x11_magic_cookies.size() == 0) - { - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, - Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); + if (x11_magic_cookies.size() == 0) + { + PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, + Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); - tm.sendAsynchronousMessage(pcof.getPayload()); + tm.sendAsynchronousMessage(pcof.getPayload()); - log.warning("Unexpected X11 request, denying it!"); + log.warning("Unexpected X11 request, denying it!"); - return; - } - } + return; + } + } - String remoteOriginatorAddress = tr.readString(); - int remoteOriginatorPort = tr.readUINT32(); + String remoteOriginatorAddress = tr.readString(); + int remoteOriginatorPort = tr.readUINT32(); - Channel c = new Channel(this); + Channel c = new Channel(this); - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } + synchronized (c) + { + c.remoteID = remoteID; + c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ + c.remoteMaxPacketSize = remoteMaxPacketSize; + c.localID = addChannel(c); + } - /* - * The open confirmation message will be sent from another thread - */ + /* + * The open confirmation message will be sent from another thread + */ - RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); - rxat.setDaemon(true); - rxat.start(); + RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); + rxat.setDaemon(true); + rxat.start(); - return; - } + return; + } - if ("forwarded-tcpip".equals(channelType)) - { - String remoteConnectedAddress = tr.readString(); /* address that was connected */ - int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ - String remoteOriginatorAddress = tr.readString(); /* originator IP address */ - int remoteOriginatorPort = tr.readUINT32(); /* originator port */ + if ("forwarded-tcpip".equals(channelType)) + { + String remoteConnectedAddress = tr.readString(); /* address that was connected */ + int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ + String remoteOriginatorAddress = tr.readString(); /* originator IP address */ + int remoteOriginatorPort = tr.readUINT32(); /* originator port */ - RemoteForwardingData rfd = null; + RemoteForwardingData rfd = null; - synchronized (remoteForwardings) - { - rfd = remoteForwardings.get(new Integer(remoteConnectedPort)); - } + synchronized (remoteForwardings) + { + rfd = remoteForwardings.get(new Integer(remoteConnectedPort)); + } - if (rfd == null) - { - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, - Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, - "No thanks, unknown port in forwarded-tcpip request", ""); + if (rfd == null) + { + PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, + Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, + "No thanks, unknown port in forwarded-tcpip request", ""); - /* Always try to be polite. */ + /* Always try to be polite. */ - tm.sendAsynchronousMessage(pcof.getPayload()); + tm.sendAsynchronousMessage(pcof.getPayload()); - log.debug("Unexpected forwarded-tcpip request, denying it!"); + log.debug("Unexpected forwarded-tcpip request, denying it!"); - return; - } + return; + } - Channel c = new Channel(this); + Channel c = new Channel(this); - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } + synchronized (c) + { + c.remoteID = remoteID; + c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ + c.remoteMaxPacketSize = remoteMaxPacketSize; + c.localID = addChannel(c); + } - /* - * The open confirmation message will be sent from another thread. - */ + /* + * The open confirmation message will be sent from another thread. + */ - RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort, - remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); - - rat.setDaemon(true); - rat.start(); - - return; - } - - if ((server_state != null) && ("session".equals(channelType))) - { - ServerConnectionCallback cb = null; - - synchronized (server_state) - { - cb = server_state.cb_conn; - } - - if (cb == null) - { - tm.sendAsynchronousMessage(new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, - "Sessions are currently not enabled", "en").getPayload()); - - return; - } - - final Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - c.state = Channel.STATE_OPEN; - c.ss = new ServerSessionImpl(c); - } - - PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, - c.localWindow, c.localMaxPacketSize); - - tm.sendAsynchronousMessage(pcoc.getPayload()); - - c.ss.sscb = cb.acceptSession(c.ss); + RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort, + remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); + + rat.setDaemon(true); + rat.start(); + + return; + } + + if ((server_state != null) && ("session".equals(channelType))) + { + ServerConnectionCallback cb = null; + + synchronized (server_state) + { + cb = server_state.cb_conn; + } + + if (cb == null) + { + tm.sendAsynchronousMessage(new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, + "Sessions are currently not enabled", "en").getPayload()); + + return; + } + + final Channel c = new Channel(this); + + synchronized (c) + { + c.remoteID = remoteID; + c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ + c.remoteMaxPacketSize = remoteMaxPacketSize; + c.localID = addChannel(c); + c.state = Channel.STATE_OPEN; + c.ss = new ServerSessionImpl(c); + } + + PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, + c.localWindow, c.localMaxPacketSize); + + tm.sendAsynchronousMessage(pcoc.getPayload()); + + c.ss.sscb = cb.acceptSession(c.ss); - return; - } - - /* Tell the server that we have no idea what it is talking about */ - - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, - "Unknown channel type", ""); - - tm.sendAsynchronousMessage(pcof.getPayload()); - - - log.warning("The peer tried to open an unsupported channel type (" + channelType + ")"); - } - - /* Starts the given runnable in a foreground (non-daemon) thread */ - private void runAsync(Runnable r) - { - Thread t = new Thread(r); - t.start(); - } - - public void msgChannelRequest(byte[] msg, int msglen) throws IOException - { - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - int id = tr.readUINT32(); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); - - ServerSessionImpl server_session = null; - - if (server_state != null) - { - synchronized (c) - { - server_session = c.ss; - } - } - - String type = tr.readString("US-ASCII"); - boolean wantReply = tr.readBoolean(); - - log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); - - if (type.equals("exit-status")) - { - if (wantReply != false) - throw new IOException( - "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true"); - - int exit_status = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - synchronized (c) - { - c.exit_status = new Integer(exit_status); - c.notifyAll(); - } - - log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); - - return; - } - - if ((server_state == null) && (type.equals("exit-signal"))) - { - if (wantReply != false) - throw new IOException( - "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true"); - - String signame = tr.readString("US-ASCII"); - tr.readBoolean(); - tr.readString(); - tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - synchronized (c) - { - c.exit_signal = signame; - c.notifyAll(); - } - - log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); - - return; - } - - if ((server_session != null) && (type.equals("pty-req"))) - { - PtySettings pty = new PtySettings(); - - pty.term = tr.readString(); - pty.term_width_characters = tr.readUINT32(); - pty.term_height_characters = tr.readUINT32(); - pty.term_width_pixels = tr.readUINT32(); - pty.term_height_pixels = tr.readUINT32(); - pty.terminal_modes = tr.readByteString(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - Runnable run_after_sending_success = null; - - ServerSessionCallback sscb = server_session.getServerSessionCallback(); - - if (sscb != null) - run_after_sending_success = sscb.requestPtyReq(server_session, pty); - - if (wantReply) - { - if (run_after_sending_success != null) - { - tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); - } - else - { - tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); - } - } - - if (run_after_sending_success != null) - { - runAsync(run_after_sending_success); - } - - return; - } - - if ((server_session != null) && (type.equals("shell"))) - { - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - Runnable run_after_sending_success = null; - ServerSessionCallback sscb = server_session.getServerSessionCallback(); - - if (sscb != null) - run_after_sending_success = sscb.requestShell(server_session); - - if (wantReply) - { - if (run_after_sending_success != null) - { - tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); - } - else - { - tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); - } - } - - if (run_after_sending_success != null) - { - runAsync(run_after_sending_success); - } - - return; - } - - if ((server_session != null) && (type.equals("exec"))) - { - String command = tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - Runnable run_after_sending_success = null; - ServerSessionCallback sscb = server_session.getServerSessionCallback(); - - if (sscb != null) - run_after_sending_success = sscb.requestExec(server_session, command); - - if (wantReply) - { - if (run_after_sending_success != null) - { - tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); - } - else - { - tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); - } - } - - if (run_after_sending_success != null) - { - runAsync(run_after_sending_success); - } - - return; - } - - /* We simply ignore unknown channel requests, however, if the server wants a reply, - * then we signal that we have no idea what it is about. - */ - - if (wantReply) - { - tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); - } - - log.debug("Channel request '" + type + "' is not known, ignoring it"); - } - - public void msgChannelEOF(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id); - - synchronized (c) - { - c.EOF = true; - c.notifyAll(); - } - - log.debug("Got SSH_MSG_CHANNEL_EOF (channel " + id + ")"); - } - - public void msgChannelClose(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); - - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("Close requested by remote"); - c.closeMessageRecv = true; - - removeChannel(c.localID); - - c.notifyAll(); - } - - log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); - } - - public void msgChannelSuccess(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id); - - synchronized (c) - { - c.successCounter++; - c.notifyAll(); - } - - log.debug("Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")"); - } - - public void msgChannelFailure(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); - - synchronized (c) - { - c.failedCounter++; - c.notifyAll(); - } + return; + } + + /* Tell the server that we have no idea what it is talking about */ + + PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, + "Unknown channel type", ""); + + tm.sendAsynchronousMessage(pcof.getPayload()); + + + log.warning("The peer tried to open an unsupported channel type (" + channelType + ")"); + } + + /* Starts the given runnable in a foreground (non-daemon) thread */ + private void runAsync(Runnable r) + { + Thread t = new Thread(r); + t.start(); + } + + public void msgChannelRequest(byte[] msg, int msglen) throws IOException + { + TypesReader tr = new TypesReader(msg, 0, msglen); + + tr.readByte(); // skip packet type + int id = tr.readUINT32(); + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); + + ServerSessionImpl server_session = null; + + if (server_state != null) + { + synchronized (c) + { + server_session = c.ss; + } + } + + String type = tr.readString("US-ASCII"); + boolean wantReply = tr.readBoolean(); + + log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); + + if (type.equals("exit-status")) + { + if (wantReply != false) + throw new IOException( + "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true"); + + int exit_status = tr.readUINT32(); + + if (tr.remain() != 0) + throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); + + synchronized (c) + { + c.exit_status = new Integer(exit_status); + c.notifyAll(); + } + + log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); + + return; + } + + if ((server_state == null) && (type.equals("exit-signal"))) + { + if (wantReply != false) + throw new IOException( + "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true"); + + String signame = tr.readString("US-ASCII"); + tr.readBoolean(); + tr.readString(); + tr.readString(); + + if (tr.remain() != 0) + throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); + + synchronized (c) + { + c.exit_signal = signame; + c.notifyAll(); + } + + log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); + + return; + } + + if ((server_session != null) && (type.equals("pty-req"))) + { + PtySettings pty = new PtySettings(); + + pty.term = tr.readString(); + pty.term_width_characters = tr.readUINT32(); + pty.term_height_characters = tr.readUINT32(); + pty.term_width_pixels = tr.readUINT32(); + pty.term_height_pixels = tr.readUINT32(); + pty.terminal_modes = tr.readByteString(); + + if (tr.remain() != 0) + throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); + + Runnable run_after_sending_success = null; + + ServerSessionCallback sscb = server_session.getServerSessionCallback(); + + if (sscb != null) + run_after_sending_success = sscb.requestPtyReq(server_session, pty); + + if (wantReply) + { + if (run_after_sending_success != null) + { + tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); + } + else + { + tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); + } + } + + if (run_after_sending_success != null) + { + runAsync(run_after_sending_success); + } + + return; + } + + if ((server_session != null) && (type.equals("subsystem"))) + { + String command = tr.readString(); + if (tr.remain() != 0) + throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); + + Runnable run_after_sending_success = null; + ServerSessionCallback sscb = server_session.getServerSessionCallback(); + + if (sscb != null) + run_after_sending_success = sscb.requestSubsystem(server_session, command); + + if (wantReply) + { + if (run_after_sending_success != null) + { + tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); + } + else + { + tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); + } + } + + if (run_after_sending_success != null) + { + runAsync(run_after_sending_success); + } + + return; + } + + if ((server_session != null) && (type.equals("shell"))) + { + if (tr.remain() != 0) + throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); + + Runnable run_after_sending_success = null; + ServerSessionCallback sscb = server_session.getServerSessionCallback(); + + if (sscb != null) + run_after_sending_success = sscb.requestShell(server_session); + + if (wantReply) + { + if (run_after_sending_success != null) + { + tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); + } + else + { + tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); + } + } + + if (run_after_sending_success != null) + { + runAsync(run_after_sending_success); + } + + return; + } + + if ((server_session != null) && (type.equals("exec"))) + { + String command = tr.readString(); + + if (tr.remain() != 0) + throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); + + Runnable run_after_sending_success = null; + ServerSessionCallback sscb = server_session.getServerSessionCallback(); + + if (sscb != null) + run_after_sending_success = sscb.requestExec(server_session, command); + + if (wantReply) + { + if (run_after_sending_success != null) + { + tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); + } + else + { + tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); + } + } + + if (run_after_sending_success != null) + { + runAsync(run_after_sending_success); + } + + return; + } + + /* We simply ignore unknown channel requests, however, if the server wants a reply, + * then we signal that we have no idea what it is about. + */ + + if (wantReply) + { + tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); + } + + log.debug("Channel request '" + type + "' is not known, ignoring it"); + } + + public void msgChannelEOF(byte[] msg, int msglen) throws IOException + { + if (msglen != 5) + throw new IOException("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")"); + + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id); + + synchronized (c) + { + c.EOF = true; + c.notifyAll(); + } + + log.debug("Got SSH_MSG_CHANNEL_EOF (channel " + id + ")"); + } + + public void msgChannelClose(byte[] msg, int msglen) throws IOException + { + if (msglen != 5) + throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")"); + + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); + + synchronized (c) + { + c.EOF = true; + c.state = Channel.STATE_CLOSED; + c.setReasonClosed("Close requested by remote"); + c.closeMessageRecv = true; + + removeChannel(c.localID); + + c.notifyAll(); + } + + log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); + } + + public void msgChannelSuccess(byte[] msg, int msglen) throws IOException + { + if (msglen != 5) + throw new IOException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")"); + + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id); + + synchronized (c) + { + c.successCounter++; + c.notifyAll(); + } + + log.debug("Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")"); + } + + public void msgChannelFailure(byte[] msg, int msglen) throws IOException + { + if (msglen != 5) + throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")"); + + int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); + + synchronized (c) + { + c.failedCounter++; + c.notifyAll(); + } - log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); - } + log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); + } - public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException - { - PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen); + public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException + { + PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen); - Channel c = getChannel(sm.recipientChannelID); + Channel c = getChannel(sm.recipientChannelID); - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " - + sm.recipientChannelID); + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " + + sm.recipientChannelID); - synchronized (c) - { - if (c.state != Channel.STATE_OPENING) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " - + sm.recipientChannelID); + synchronized (c) + { + if (c.state != Channel.STATE_OPENING) + throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " + + sm.recipientChannelID); - c.remoteID = sm.senderChannelID; - c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = sm.maxPacketSize; - c.state = Channel.STATE_OPEN; - c.notifyAll(); - } + c.remoteID = sm.senderChannelID; + c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */ + c.remoteMaxPacketSize = sm.maxPacketSize; + c.state = Channel.STATE_OPEN; + c.notifyAll(); + } - log.debug("Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: " - + sm.senderChannelID + ")"); - } + log.debug("Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: " + + sm.senderChannelID + ")"); + } - public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException - { - if (msglen < 5) - throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")"); - - TypesReader tr = new TypesReader(msg, 0, msglen); + public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException + { + if (msglen < 5) + throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")"); + + TypesReader tr = new TypesReader(msg, 0, msglen); - tr.readByte(); // skip packet type - int id = tr.readUINT32(); /* sender channel */ - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); - - int reasonCode = tr.readUINT32(); - String description = tr.readString("UTF-8"); - - String reasonCodeSymbolicName = null; - - switch (reasonCode) - { - case 1: - reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; - break; - case 2: - reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; - break; - case 3: - reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; - break; - case 4: - reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; - break; - default: - reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; - } - - StringBuilder descriptionBuffer = new StringBuilder(); - descriptionBuffer.append(description); - - for (int i = 0; i < descriptionBuffer.length(); i++) - { - char cc = descriptionBuffer.charAt(i); - - if ((cc >= 32) && (cc <= 126)) - continue; - descriptionBuffer.setCharAt(i, '\uFFFD'); - } - - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '" - + descriptionBuffer.toString() + "')"); - c.notifyAll(); - } - - log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); - } - - public void msgGlobalRequest(byte[] msg, int msglen) throws IOException - { - /* Currently we do not support any kind of global request */ - - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - String requestName = tr.readString(); - boolean wantReply = tr.readBoolean(); - - if (wantReply) - { - byte[] reply_failure = new byte[1]; - reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; - - tm.sendAsynchronousMessage(reply_failure); - } - - /* We do not clean up the requestName String - that is OK for debug */ - - log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); - } - - public void msgGlobalSuccess() throws IOException - { - synchronized (channels) - { - globalSuccessCounter++; - channels.notifyAll(); - } - - log.debug("Got SSH_MSG_REQUEST_SUCCESS"); - } - - public void msgGlobalFailure() throws IOException - { - synchronized (channels) - { - globalFailedCounter++; - channels.notifyAll(); - } - - log.debug("Got SSH_MSG_REQUEST_FAILURE"); - } - - public void handleMessage(byte[] msg, int msglen) throws IOException - { - if (msg == null) - { - - log.debug("HandleMessage: got shutdown"); - - synchronized (listenerThreads) - { - for (IChannelWorkerThread lat : listenerThreads) - { - lat.stopWorking(); - } - listenerThreadsAllowed = false; - } - - synchronized (channels) - { - shutdown = true; - - for (Channel c : channels) - { - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("The connection is being shutdown"); - c.closeMessageRecv = true; /* - * You never know, perhaps - * we are waiting for a - * pending close message - * from the server... - */ - c.notifyAll(); - } - } - - channels.clear(); - channels.notifyAll(); /* Notify global response waiters */ - return; - } - } - - switch (msg[0]) - { - case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: - msgChannelOpenConfirmation(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: - msgChannelWindowAdjust(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_DATA: - msgChannelData(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: - msgChannelExtendedData(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_REQUEST: - msgChannelRequest(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_EOF: - msgChannelEOF(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_OPEN: - msgChannelOpen(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_CLOSE: - msgChannelClose(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_SUCCESS: - msgChannelSuccess(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_FAILURE: - msgChannelFailure(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: - msgChannelOpenFailure(msg, msglen); - break; - case Packets.SSH_MSG_GLOBAL_REQUEST: - msgGlobalRequest(msg, msglen); - break; - case Packets.SSH_MSG_REQUEST_SUCCESS: - msgGlobalSuccess(); - break; - case Packets.SSH_MSG_REQUEST_FAILURE: - msgGlobalFailure(); - break; - default: - throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff)); - } - } + tr.readByte(); // skip packet type + int id = tr.readUINT32(); /* sender channel */ + + Channel c = getChannel(id); + + if (c == null) + throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); + + int reasonCode = tr.readUINT32(); + String description = tr.readString("UTF-8"); + + String reasonCodeSymbolicName = null; + + switch (reasonCode) + { + case 1: + reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; + break; + case 2: + reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; + break; + case 3: + reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; + break; + case 4: + reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; + break; + default: + reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; + } + + StringBuilder descriptionBuffer = new StringBuilder(); + descriptionBuffer.append(description); + + for (int i = 0; i < descriptionBuffer.length(); i++) + { + char cc = descriptionBuffer.charAt(i); + + if ((cc >= 32) && (cc <= 126)) + continue; + descriptionBuffer.setCharAt(i, '\uFFFD'); + } + + synchronized (c) + { + c.EOF = true; + c.state = Channel.STATE_CLOSED; + c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '" + + descriptionBuffer.toString() + "')"); + c.notifyAll(); + } + + log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); + } + + public void msgGlobalRequest(byte[] msg, int msglen) throws IOException + { + /* Currently we do not support any kind of global request */ + + TypesReader tr = new TypesReader(msg, 0, msglen); + + tr.readByte(); // skip packet type + String requestName = tr.readString(); + boolean wantReply = tr.readBoolean(); + + if (wantReply) + { + byte[] reply_failure = new byte[1]; + reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; + + tm.sendAsynchronousMessage(reply_failure); + } + + /* We do not clean up the requestName String - that is OK for debug */ + + log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); + } + + public void msgGlobalSuccess() throws IOException + { + synchronized (channels) + { + globalSuccessCounter++; + channels.notifyAll(); + } + + log.debug("Got SSH_MSG_REQUEST_SUCCESS"); + } + + public void msgGlobalFailure() throws IOException + { + synchronized (channels) + { + globalFailedCounter++; + channels.notifyAll(); + } + + log.debug("Got SSH_MSG_REQUEST_FAILURE"); + } + + public void handleMessage(byte[] msg, int msglen) throws IOException + { + if (msg == null) + { + + log.debug("HandleMessage: got shutdown"); + + synchronized (listenerThreads) + { + for (IChannelWorkerThread lat : listenerThreads) + { + lat.stopWorking(); + } + listenerThreadsAllowed = false; + } + + synchronized (channels) + { + shutdown = true; + + for (Channel c : channels) + { + synchronized (c) + { + c.EOF = true; + c.state = Channel.STATE_CLOSED; + c.setReasonClosed("The connection is being shutdown"); + c.closeMessageRecv = true; /* + * You never know, perhaps + * we are waiting for a + * pending close message + * from the server... + */ + c.notifyAll(); + } + } + + channels.clear(); + channels.notifyAll(); /* Notify global response waiters */ + return; + } + } + + switch (msg[0]) + { + case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: + msgChannelOpenConfirmation(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: + msgChannelWindowAdjust(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_DATA: + msgChannelData(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: + msgChannelExtendedData(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_REQUEST: + msgChannelRequest(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_EOF: + msgChannelEOF(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_OPEN: + msgChannelOpen(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_CLOSE: + msgChannelClose(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_SUCCESS: + msgChannelSuccess(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_FAILURE: + msgChannelFailure(msg, msglen); + break; + case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: + msgChannelOpenFailure(msg, msglen); + break; + case Packets.SSH_MSG_GLOBAL_REQUEST: + msgGlobalRequest(msg, msglen); + break; + case Packets.SSH_MSG_REQUEST_SUCCESS: + msgGlobalSuccess(); + break; + case Packets.SSH_MSG_REQUEST_FAILURE: + msgGlobalFailure(); + break; + default: + throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff)); + } + } }