Merge "Web UI Branding support This fix provides an extensible branding support with...
authorAndrew Kim <andrekim@cisco.com>
Sat, 6 Apr 2013 01:45:23 +0000 (01:45 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 6 Apr 2013 01:45:23 +0000 (01:45 +0000)
69 files changed:
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml
opendaylight/protocol_plugins/openflow/pom.xml
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageReadWrite.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/ISwitch.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/PriorityMessage.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java
opendaylight/routing/dijkstra_implementation/src/main/java/org/opendaylight/controller/routing/dijkstra_implementation/internal/Activator.java
opendaylight/routing/dijkstra_implementation/src/main/java/org/opendaylight/controller/routing/dijkstra_implementation/internal/DijkstraImplementation.java
opendaylight/routing/dijkstra_implementation/src/main/resources/OSGI-INF/component-factory.xml [deleted file]
opendaylight/routing/dijkstra_implementation/src/main/resources/OSGI-INF/component.xml [deleted file]
opendaylight/sal/yang-prototype/code-generator/pom.xml
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/.gitignore [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/CombineTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToResourcesPluginTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/resources/model/testfile1.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/resources/model/testfile2.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct_combined/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct_resources/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoGenerators/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoGenerators_resources/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoYangFiles/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/UnknownGenerator/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/YangRootNotExist/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateResourcesTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/resources/mock.yang [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java [moved from opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/BrokerServiceImpl.java with 52% similarity]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/main/java/org/opendaylight/controller/yang2sources/spi/ResourceGenerator.java [moved from opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/data/package-info.java with 58% similarity]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/test/java/org/opendaylight/controller/yang2sources/spi/ResourceProviderTestImpl.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataProviderService.java
opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataRefresher.java
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/MappingProvider.java
opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/pom.xml
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/BrokerImpl.java
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/ConsumerSessionImpl.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/DataBrokerModule.java [moved from opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/data/DataBrokerModule.java with 86% similarity]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/NotificationModule.java [moved from opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/notify/NotificationModule.java with 86% similarity]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/ProviderSessionImpl.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/notify/package-info.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/rpc/RpcModule.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/rpc/package-info.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-common-util/pom.xml [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java [moved from opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/RpcUtils.java with 60% similarity]
opendaylight/sal/yang-prototype/sal/sal-core-api/pom.xml
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java
opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-core-demo/src/main/java/org/opendaylight/controller/sal/demo/SALDemo.java
opendaylight/web/root/src/main/resources/js/one-topology.js

index a9667d805494f92e2caa23b3f2f703e9f234549f..da818d79eeb9914e7ffb04ef332e800b2b2f24ac 100644 (file)
@@ -71,7 +71,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
 
     void unsetDataPacketService(IDataPacketService s) {
         if (this.dataPacketService == s) {
-            this.dataPacketService = s;
+            this.dataPacketService = null;
         }
     }
 
index 1b90fc77980413422f1f782fb948d487fe6ad0be..5cababb85b461b697464dc44b7134e829e0c90ca 100644 (file)
@@ -48,3 +48,19 @@ org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
 # of.listenPort=6633
 # The time (in milliseconds) the controller will wait for a response after sending a Barrier Request or a Statistic Request message (default 2000 msec)
 # of.messageResponseTimer=2000
+
+# TLS configuration
+# To enable TLS, set secureChannelEnabled=true and specify the location of controller Java KeyStore and TrustStore files.
+# The Java KeyStore contains controller's private key and certificate. The Java TrustStore contains the trusted certificate 
+# entries, including switches' Certification Authority (CA) certificates. For example,
+# secureChannelEnabled=true
+# controllerKeyStore=./configuration/ctlKeyStore
+# controllerKeyStorePassword=xxxxx (this password should match the password used for KeyStore generation)
+# controllerTrustStore=./configuration/ctlTrustStore
+# controllerTrustStorePassword=xxxxx (this password should match the password used for TrustStore generation)
+
+secureChannelEnabled=false
+controllerKeyStore=
+controllerKeyStorePassword=
+controllerTrustStore=
+controllerTrustStorePassword=
index 3c3f78889f4cc726491e77b41f14e670d08799af..a99d17d37c25de4816fc108da4a0e5879326fa2b 100644 (file)
@@ -36,6 +36,9 @@
   <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.InventoryServiceShim" level="INFO"/>
   <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.TopologyServices" level="INFO"/>
   <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.TopologyServiceShim" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.Controller" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchHandler" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchIOSecureService" level="INFO"/>
   <!-- SAL  -->
   <logger name="org.opendaylight.controller.sal" level="INFO"/>
   <logger name="org.opendaylight.controller.sal.implementation" level="INFO"/>
index 418c897b52134c6e20b3b57e44acd65b07b244cd..614b0ff81826bea3b74c7d4219bdea0c7b653aca 100644 (file)
@@ -38,7 +38,8 @@
               org.apache.felix.dm,
               org.slf4j,
               org.eclipse.osgi.framework.console,
-                         org.osgi.framework
+                         org.osgi.framework,
+                         javax.net.ssl
             </Import-Package>
             <Export-Package>
                          org.opendaylight.controller.protocol_plugin.openflow.internal
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageReadWrite.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/IMessageReadWrite.java
new file mode 100644 (file)
index 0000000..301159d
--- /dev/null
@@ -0,0 +1,45 @@
+
+/*
+ * 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.protocol_plugin.openflow.core;
+
+import java.util.List;
+
+import org.openflow.protocol.OFMessage;
+
+/**
+ * This interface defines low level routines to read/write messages on an open
+ * socket channel. If secure communication is desired, these methods also perform
+ * encryption and decryption of the network data.
+ */
+public interface IMessageReadWrite {
+       /**
+        * Sends the OF message out over the socket channel. For secure
+        * communication, the data will be encrypted.
+        * 
+        * @param msg OF message to be sent
+        * @throws Exception
+        */
+       public void asyncSend(OFMessage msg) throws Exception;
+
+       /**
+        * Resumes sending the remaining messages in the outgoing buffer
+        * @throws Exception
+        */
+       public void resumeSend() throws Exception;
+
+       /**
+        * Reads the incoming network data from the socket and retrieves the OF
+        * messages. For secure communication, the data will be decrypted first.
+        * 
+        * @return list of OF messages
+        * @throws Exception
+        */
+    public List<OFMessage> readMessages() throws Exception;
+}
index 0a4560ee0f68a1fc7eb48662dcc178a5f3184f25..a15c2e5c715c95d89203a15b25dc95ebc185506c 100644 (file)
@@ -66,20 +66,52 @@ public interface ISwitch {
        public Date getConnectedDate();
 
        /**
-        * Sends the message. A unique XID is generated automatically and inserted into the message.
-        * @param msg TheOF message to be sent
+        * This method puts the message in an outgoing priority queue with normal
+        * priority. It will be served after high priority messages. The method
+        * should be used for non-critical messages such as statistics request,
+        * discovery packets, etc. An unique XID is generated automatically and
+        * inserted into the message.
+        * 
+        * @param msg The OF message to be sent
         * @return The XID used
         */
        public Integer asyncSend(OFMessage msg);
 
        /**
-        * Sends the message with the specified XID.
+        * This method puts the message in an outgoing priority queue with normal
+        * priority. It will be served after high priority messages. The method
+        * should be used for non-critical messages such as statistics request,
+        * discovery packets, etc. The specified XID is inserted into the message.
+        * 
         * @param msg The OF message to be Sent
         * @param xid The XID to be used in the message
         * @return The XID used
         */
        public Integer asyncSend(OFMessage msg, int xid);
 
+       /**
+        * This method puts the message in an outgoing priority queue with high
+        * priority. It will be served first before normal priority messages. The
+        * method should be used for critical messages such as hello, echo reply
+        * etc. An unique XID is generated automatically and inserted into the
+        * message.
+        * 
+        * @param msg The OF message to be sent
+        * @return The XID used
+        */
+       public Integer asyncFastSend(OFMessage msg);
+
+       /**
+        * This method puts the message in an outgoing priority queue with high
+        * priority. It will be served first before normal priority messages. The
+        * method should be used for critical messages such as hello, echo reply
+        * etc. The specified XID is inserted into the message.
+        * 
+        * @param msg The OF message to be sent
+        * @return The XID used
+        */
+       public Integer asyncFastSend(OFMessage msg, int xid);
+
        /**
         * Sends the OF message followed by a Barrier Request with a unique XID which is automatically generated,
         * and waits for a result from the switch.
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java
new file mode 100644 (file)
index 0000000..d20bf1e
--- /dev/null
@@ -0,0 +1,142 @@
+
+/*
+ * 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.protocol_plugin.openflow.core.internal;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.List;
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageReadWrite;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.factory.BasicFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements methods to read/write messages over an established
+ * socket channel. The data exchange is in clear text format.
+ */
+public class MessageReadWriteService implements IMessageReadWrite {
+    private static final Logger logger = LoggerFactory
+            .getLogger(MessageReadWriteService.class);
+    private static final int bufferSize = 1024 * 1024;
+
+    private Selector selector;
+    private SelectionKey clientSelectionKey;
+    private SocketChannel socket;
+    private ByteBuffer inBuffer;
+    private ByteBuffer outBuffer;
+    private BasicFactory factory;
+
+    public MessageReadWriteService(SocketChannel socket, Selector selector) throws ClosedChannelException {
+       this.socket = socket;
+       this.selector = selector;
+       this.factory = new BasicFactory();
+       this.inBuffer = ByteBuffer.allocateDirect(bufferSize);
+       this.outBuffer = ByteBuffer.allocateDirect(bufferSize);
+       this.clientSelectionKey = this.socket.register(this.selector,
+                       SelectionKey.OP_READ);
+    }
+
+       /**
+        * Sends the OF message out over the socket channel.
+        * 
+        * @param msg OF message to be sent
+        * @throws Exception
+        */
+    @Override
+    public void asyncSend(OFMessage msg) throws IOException {
+       synchronized (outBuffer) {
+               int msgLen = msg.getLengthU();
+               if (outBuffer.remaining() < msgLen) {
+                       // increase the buffer size so that it can contain this message
+                       ByteBuffer newBuffer = ByteBuffer.allocateDirect(outBuffer
+                                       .capacity()
+                                       + msgLen);
+                       outBuffer.flip();
+                       newBuffer.put(outBuffer);
+                       outBuffer = newBuffer;
+               }
+               msg.writeTo(outBuffer);
+
+               if (!socket.isOpen()) {
+                       return;
+               }
+
+               outBuffer.flip();
+               socket.write(outBuffer);
+               outBuffer.compact();
+               if (outBuffer.position() > 0) {
+                       this.clientSelectionKey = this.socket.register(
+                                       this.selector, SelectionKey.OP_WRITE, this);
+               }
+               logger.trace("Message sent: {}", msg.toString());
+       }
+    }
+
+       /**
+        * Resumes sending the remaining messages in the outgoing buffer
+        * @throws Exception
+        */
+    @Override
+    public void resumeSend() throws IOException {
+               synchronized (outBuffer) {
+                       if (!socket.isOpen()) {
+                               return;
+                       }
+
+               outBuffer.flip();
+               socket.write(outBuffer);
+               outBuffer.compact();
+               if (outBuffer.position() > 0) {
+                       this.clientSelectionKey = this.socket.register(
+                                       this.selector, SelectionKey.OP_WRITE, this);
+               } else {
+                       this.clientSelectionKey = this.socket.register(
+                                       this.selector, SelectionKey.OP_READ, this);
+               }
+        }
+    }
+
+       /**
+        * Reads the incoming network data from the socket and retrieves the OF
+        * messages.
+        * 
+        * @return list of OF messages
+        * @throws Exception
+        */
+    @Override
+    public List<OFMessage> readMessages() throws IOException {
+               if (!socket.isOpen()) {
+                       return null;
+               }
+
+               List<OFMessage> msgs = null;
+        int bytesRead = -1;        
+        bytesRead = socket.read(inBuffer);
+        if (bytesRead < 0) {
+                       throw new AsynchronousCloseException();
+        }
+
+        inBuffer.flip();
+        msgs = factory.parseMessages(inBuffer);
+        if (inBuffer.hasRemaining()) {
+            inBuffer.compact();
+        } else {
+            inBuffer.clear();
+        }
+        return msgs;
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/PriorityMessage.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/PriorityMessage.java
new file mode 100644 (file)
index 0000000..6bc4f10
--- /dev/null
@@ -0,0 +1,59 @@
+
+/*
+ * 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.protocol_plugin.openflow.core.internal;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openflow.protocol.OFMessage;
+
+/**
+ * This class describes an OpenFlow message with priority
+ */
+class PriorityMessage {
+       OFMessage msg;
+       int priority;
+       
+       public PriorityMessage(OFMessage msg, int priority) {
+               this.msg = msg;
+               this.priority = priority;
+       }
+
+       public OFMessage getMsg() {
+               return msg;
+       }
+
+       public void setMsg(OFMessage msg) {
+               this.msg = msg;
+       }
+
+       public int getPriority() {
+               return priority;
+       }
+
+       public void setPriority(int priority) {
+               this.priority = priority;
+       }       
+       
+       @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+    @Override
+    public String toString() {
+        return "PriorityMessage[" + ReflectionToStringBuilder.toString(this) + "]";
+    }
+}
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
new file mode 100644 (file)
index 0000000..627e223
--- /dev/null
@@ -0,0 +1,346 @@
+
+/*
+ * 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.protocol_plugin.openflow.core.internal;
+
+import java.io.FileInputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.List;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageReadWrite;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.factory.BasicFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements methods to read/write messages over an established
+ * socket channel. The data exchange is encrypted/decrypted by SSLEngine.
+ */
+public class SecureMessageReadWriteService implements IMessageReadWrite {
+    private static final Logger logger = LoggerFactory
+            .getLogger(SecureMessageReadWriteService.class);
+
+    private Selector selector;
+    private SelectionKey clientSelectionKey;
+    private SocketChannel socket;
+    private BasicFactory factory;
+
+    private SSLEngine sslEngine;
+       private SSLEngineResult sslEngineResult;        // results from sslEngine last operation
+    private ByteBuffer myAppData;                              // clear text message to be sent
+    private ByteBuffer myNetData;                      // encrypted message to be sent
+    private ByteBuffer peerAppData;                            // clear text message received from the switch
+    private ByteBuffer peerNetData;                    // encrypted message from the switch
+
+    public SecureMessageReadWriteService(SocketChannel socket, Selector selector) throws Exception {
+       this.socket = socket;
+       this.selector = selector;
+       this.factory = new BasicFactory();
+
+       createSecureChannel(socket);
+       createBuffers(sslEngine);
+    }
+
+       /**
+        * Bring up secure channel using SSL Engine
+        * 
+        * @param socket TCP socket channel
+        * @throws Exception
+        */
+    private void createSecureChannel(SocketChannel socket) throws Exception {
+       String keyStoreFile = System.getProperty("controllerKeyStore");
+       String keyStorePassword = System.getProperty("controllerKeyStorePassword");
+       String trustStoreFile = System.getProperty("controllerTrustStore");;
+       String trustStorePassword = System.getProperty("controllerTrustStorePassword");;
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        ks.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray());
+        ts.load(new FileInputStream(trustStoreFile), trustStorePassword.toCharArray());
+        kmf.init(ks, keyStorePassword.toCharArray());
+        tmf.init(ts);
+
+        SecureRandom random = new SecureRandom();
+        random.nextInt();
+
+       SSLContext sslContext = SSLContext.getInstance("TLS");
+        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), random);
+       sslEngine = sslContext.createSSLEngine();
+       sslEngine.setUseClientMode(false);
+       sslEngine.setNeedClientAuth(true);
+       
+       // Do initial handshake
+       doHandshake(socket, sslEngine);
+       
+        this.clientSelectionKey = this.socket.register(this.selector,
+                SelectionKey.OP_READ);
+    }
+
+       /**
+        * Sends the OF message out over the socket channel. The message is
+        * encrypted by SSL Engine.
+        * 
+        * @param msg OF message to be sent
+        * @throws Exception
+        */
+    @Override
+    public void asyncSend(OFMessage msg) throws Exception {
+       synchronized (myAppData) {
+               int msgLen = msg.getLengthU();
+               if (myAppData.remaining() < msgLen) {
+                       // increase the buffer size so that it can contain this message
+                       ByteBuffer newBuffer = ByteBuffer.allocateDirect(myAppData
+                                       .capacity()
+                                       + msgLen);
+                       myAppData.flip();
+                       newBuffer.put(myAppData);
+                       myAppData = newBuffer;
+               }
+               msg.writeTo(myAppData);
+               myAppData.flip();
+               sslEngineResult = sslEngine.wrap(myAppData, myNetData);
+               logger.trace("asyncSend sslEngine wrap: {}", sslEngineResult);
+               runDelegatedTasks(sslEngineResult, sslEngine);
+
+               if (!socket.isOpen()) {
+                       return;
+               }
+
+               myNetData.flip();
+               socket.write(myNetData);
+               if (myNetData.hasRemaining()) {
+                       myNetData.compact();
+               } else {
+                       myNetData.clear();
+               }
+
+               if (myAppData.hasRemaining()) {
+                       myAppData.compact();
+                       this.clientSelectionKey = this.socket.register(
+                                       this.selector, SelectionKey.OP_WRITE, this);
+               } else {
+                       myAppData.clear();
+                       this.clientSelectionKey = this.socket.register(
+                                       this.selector, SelectionKey.OP_READ, this);
+               }
+
+               logger.trace("Message sent: {}", msg.toString());
+       }
+    }
+
+       /**
+        * Resumes sending the remaining messages in the outgoing buffer
+        * @throws Exception
+        */
+    @Override
+    public void resumeSend() throws Exception {
+               synchronized (myAppData) {
+                       myAppData.flip();
+                       sslEngineResult = sslEngine.wrap(myAppData, myNetData);
+                       logger.trace("resumeSend sslEngine wrap: {}", sslEngineResult);
+                       runDelegatedTasks(sslEngineResult, sslEngine);
+
+                       if (!socket.isOpen()) {
+                               return;
+                       }
+
+                       myNetData.flip();
+                       socket.write(myNetData);
+                       if (myNetData.hasRemaining()) {
+                               myNetData.compact();
+                       } else {
+                               myNetData.clear();
+                       }
+
+                       if (myAppData.hasRemaining()) {
+                               myAppData.compact();
+                               this.clientSelectionKey = this.socket.register(this.selector,
+                                               SelectionKey.OP_WRITE, this);
+                       } else {
+                               myAppData.clear();
+                               this.clientSelectionKey = this.socket.register(this.selector,
+                                               SelectionKey.OP_READ, this);
+                       }
+               }
+    }
+
+       /**
+        * Reads the incoming network data from the socket, decryptes them and then
+        * retrieves the OF messages.
+        * 
+        * @return list of OF messages
+        * @throws Exception
+        */
+    @Override
+    public List<OFMessage> readMessages() throws Exception {
+               if (!socket.isOpen()) {
+                       return null;
+               }
+
+               List<OFMessage> msgs = null;
+        int bytesRead = -1;
+       int countDown = 50;             
+
+       bytesRead = socket.read(peerNetData);
+       if (bytesRead < 0) {
+                       throw new AsynchronousCloseException();
+       }
+
+       do {                    
+               peerNetData.flip();
+               sslEngineResult = sslEngine.unwrap(peerNetData, peerAppData);
+               if (peerNetData.hasRemaining()) {
+                       peerNetData.compact();
+               } else {
+                       peerNetData.clear();
+               }
+               logger.trace("sslEngine unwrap result: {}", sslEngineResult);
+               runDelegatedTasks(sslEngineResult, sslEngine);
+       } while ((sslEngineResult.getStatus() == SSLEngineResult.Status.OK) &&
+                         peerNetData.hasRemaining() && (--countDown > 0));
+       
+       if (countDown == 0) {
+               logger.trace("countDown reaches 0. peerNetData pos {} lim {}", peerNetData.position(), peerNetData.limit());
+       }
+
+       peerAppData.flip();
+       msgs = factory.parseMessages(peerAppData);
+       if (peerAppData.hasRemaining()) {
+               peerAppData.compact();
+       } else {
+               peerAppData.clear();
+       }
+
+       this.clientSelectionKey = this.socket.register(
+                       this.selector, SelectionKey.OP_READ, this);
+        
+        return msgs;
+    }
+
+    /**
+     *  If the result indicates that we have outstanding tasks to do,
+     *  go ahead and run them in this thread.
+     */
+    private void runDelegatedTasks(SSLEngineResult result,
+               SSLEngine engine) throws Exception {
+
+       if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+               Runnable runnable;
+               while ((runnable = engine.getDelegatedTask()) != null) {
+                       logger.debug("\trunning delegated task...");
+                       runnable.run();
+               }
+               HandshakeStatus hsStatus = engine.getHandshakeStatus();
+               if (hsStatus == HandshakeStatus.NEED_TASK) {
+                       throw new Exception(
+                                       "handshake shouldn't need additional tasks");
+               }
+               logger.debug("\tnew HandshakeStatus: {}", hsStatus);
+       }
+    }
+
+    private void doHandshake(SocketChannel socket, SSLEngine engine) throws Exception {
+       SSLSession session = engine.getSession();
+       ByteBuffer myAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
+       ByteBuffer peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
+       ByteBuffer myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
+       ByteBuffer peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
+
+       // Begin handshake
+       engine.beginHandshake();
+       SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
+
+       // Process handshaking message
+       while (hs != SSLEngineResult.HandshakeStatus.FINISHED &&
+                  hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+               switch (hs) {
+               case NEED_UNWRAP:
+                       // Receive handshaking data from peer
+                       if (socket.read(peerNetData) < 0) {
+                               throw new AsynchronousCloseException();
+                       }
+
+                       // Process incoming handshaking data
+                       peerNetData.flip();
+                       SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
+                       peerNetData.compact();
+                       hs = res.getHandshakeStatus();
+
+                       // Check status
+                       switch (res.getStatus()) {
+                       case OK :
+                               // Handle OK status
+                               break;
+                       }
+                       break;
+
+               case NEED_WRAP :
+                       // Empty the local network packet buffer.
+                       myNetData.clear();
+
+                       // Generate handshaking data
+                       res = engine.wrap(myAppData, myNetData);
+                       hs = res.getHandshakeStatus();
+
+                       // Check status
+                       switch (res.getStatus()) {
+                       case OK :
+                               myNetData.flip();
+
+                               // Send the handshaking data to peer
+                               while (myNetData.hasRemaining()) {
+                                       if (socket.write(myNetData) < 0) {
+                                       throw new AsynchronousCloseException();
+                                       }
+                               }
+                               break;
+                       }
+                       break;
+
+               case NEED_TASK :
+                       // Handle blocking tasks
+                       Runnable runnable;
+                       while ((runnable = engine.getDelegatedTask()) != null) {
+                               logger.debug("\trunning delegated task...");
+                               runnable.run();
+                       }
+                       hs = engine.getHandshakeStatus();
+                       if (hs == HandshakeStatus.NEED_TASK) {
+                               throw new Exception(
+                                               "handshake shouldn't need additional tasks");
+                       }
+                       logger.debug("\tnew HandshakeStatus: {}", hs);
+                       break;
+               }
+       }
+    }
+    
+    private void createBuffers(SSLEngine engine) {
+       SSLSession session = engine.getSession();
+       this.myAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
+       this.peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
+       this.myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
+       this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
+    }
+}
index 8881fb53640caa58e692a08bdbdbb7bbb80916e6..45203758bdd45e13486936faab73c27f947f547d 100644 (file)
@@ -9,12 +9,13 @@
 
 package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
 
-import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.spi.SelectorProvider;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -28,11 +29,13 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.PriorityBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageReadWrite;
 import org.openflow.protocol.OFBarrierReply;
 import org.openflow.protocol.OFEchoReply;
 import org.openflow.protocol.OFError;
@@ -63,7 +66,6 @@ public class SwitchHandler implements ISwitch {
     private static final int SWITCH_LIVENESS_TIMER = 5000;
     private static final int SWITCH_LIVENESS_TIMEOUT = 2 * SWITCH_LIVENESS_TIMER + 500;
     private int MESSAGE_RESPONSE_TIMER = 2000;
-    private static final int bufferSize = 1024 * 1024;
 
     private String instanceName;
     private ISwitch thisISwitch;
@@ -74,10 +76,7 @@ public class SwitchHandler implements ISwitch {
     private Byte tables;
     private Integer actions;
     private Selector selector;
-    private SelectionKey clientSelectionKey;
     private SocketChannel socket;
-    private ByteBuffer inBuffer;
-    private ByteBuffer outBuffer;
     private BasicFactory factory;
     private AtomicInteger xid;
     private SwitchState state;
@@ -90,9 +89,12 @@ public class SwitchHandler implements ISwitch {
     private ExecutorService executor;
     private ConcurrentHashMap<Integer, Callable<Object>> messageWaitingDone;
     private boolean running;
+    private IMessageReadWrite msgReadWriteService;
     private Thread switchHandlerThread;
     private Integer responseTimerValue;
-
+       private PriorityBlockingQueue<PriorityMessage> transmitQ;
+    private Thread transmitThread;
+    
     private enum SwitchState {
         NON_OPERATIONAL(0), WAIT_FEATURES_REPLY(1), WAIT_CONFIG_REPLY(2), OPERATIONAL(
                 3);
@@ -130,44 +132,37 @@ public class SwitchHandler implements ISwitch {
         this.periodicTimer = null;
         this.executor = Executors.newFixedThreadPool(4);
         this.messageWaitingDone = new ConcurrentHashMap<Integer, Callable<Object>>();
-        this.inBuffer = ByteBuffer.allocateDirect(bufferSize);
-        this.outBuffer = ByteBuffer.allocateDirect(bufferSize);
         this.responseTimerValue = MESSAGE_RESPONSE_TIMER;
         String rTimer = System.getProperty("of.messageResponseTimer");
         if (rTimer != null) {
-            try {
-                responseTimerValue = Integer.decode(rTimer);
-            } catch (NumberFormatException e) {
-                logger.warn("Invalid of.messageResponseTimer:" + rTimer + ", use default("
-                        + MESSAGE_RESPONSE_TIMER+ ")");
-            }
+               try {
+                       responseTimerValue = Integer.decode(rTimer);
+               } catch (NumberFormatException e) {
+                               logger.warn("Invalid of.messageResponseTimer: {} use default({})",
+                                               rTimer, MESSAGE_RESPONSE_TIMER);
+               }
         }
-    }
+       }
 
     public void start() {
         try {
-            this.selector = SelectorProvider.provider().openSelector();
-            this.socket.configureBlocking(false);
-            this.socket.socket().setTcpNoDelay(true);
-            this.clientSelectionKey = this.socket.register(this.selector,
-                    SelectionKey.OP_READ);
+               startTransmitThread();
+               setupCommChannel();
+               sendFirstHello();
             startHandlerThread();
         } catch (Exception e) {
             reportError(e);
-            return;
         }
     }
 
     private void startHandlerThread() {
-        OFMessage msg = factory.getMessage(OFType.HELLO);
-        asyncSend(msg);
         switchHandlerThread = new Thread(new Runnable() {
             @Override
             public void run() {
                 running = true;
                 while (running) {
                     try {
-                        // wait for an incoming connection
+                       // wait for an incoming connection
                         selector.select(0);
                         Iterator<SelectionKey> selectedKeys = selector
                                 .selectedKeys().iterator();
@@ -195,7 +190,7 @@ public class SwitchHandler implements ISwitch {
             running = false;
             selector.wakeup();
             cancelSwitchTimer();
-            this.clientSelectionKey.cancel();
+            this.selector.close();
             this.socket.close();
             executor.shutdown();
         } catch (Exception e) {
@@ -209,77 +204,94 @@ public class SwitchHandler implements ISwitch {
         return this.xid.incrementAndGet();
     }
 
+       /**
+        * This method puts the message in an outgoing priority queue with normal
+        * priority. It will be served after high priority messages. The method
+        * should be used for non-critical messages such as statistics request,
+        * discovery packets, etc. An unique XID is generated automatically and
+        * inserted into the message.
+        * 
+        * @param msg The OF message to be sent
+        * @return The XID used
+        */
     @Override
     public Integer asyncSend(OFMessage msg) {
-        return asyncSend(msg, getNextXid());
+       return asyncSend(msg, getNextXid());
+    }
+
+       /**
+        * This method puts the message in an outgoing priority queue with normal
+        * priority. It will be served after high priority messages. The method
+        * should be used for non-critical messages such as statistics request,
+        * discovery packets, etc. The specified XID is inserted into the message.
+        * 
+        * @param msg The OF message to be Sent
+        * @param xid The XID to be used in the message
+        * @return The XID used
+        */
+    @Override
+    public Integer asyncSend(OFMessage msg, int xid) {
+       msg.setXid(xid);
+       transmitQ.add(new PriorityMessage(msg, 0));
+        return xid;
     }
 
+       /**
+        * This method puts the message in an outgoing priority queue with high
+        * priority. It will be served first before normal priority messages. The
+        * method should be used for critical messages such as hello, echo reply
+        * etc. An unique XID is generated automatically and inserted into the
+        * message.
+        * 
+        * @param msg The OF message to be sent
+        * @return The XID used
+        */
     @Override
-    public Integer asyncSend(OFMessage msg, int xid) {
-        synchronized (outBuffer) {
-            /*
-            if ((msg.getType() != OFType.ECHO_REQUEST) &&
-                       (msg.getType() != OFType.ECHO_REPLY)) {
-               logger.debug("sending " + msg.getType().toString() + " to " + toString());
-            }
-             */
-            msg.setXid(xid);
-            int msgLen = msg.getLengthU();
-            if (outBuffer.remaining() < msgLen) {
-                // increase the buffer size so that it can contain this message
-                ByteBuffer newBuffer = ByteBuffer.allocateDirect(outBuffer
-                        .capacity()
-                        + msgLen);
-                outBuffer.flip();
-                newBuffer.put(outBuffer);
-                outBuffer = newBuffer;
-            }
-            msg.writeTo(outBuffer);
-            outBuffer.flip();
-            try {
-                socket.write(outBuffer);
-                outBuffer.compact();
-                if (outBuffer.position() > 0) {
-                    this.clientSelectionKey = this.socket.register(
-                            this.selector, SelectionKey.OP_WRITE, this);
-                }
-                logger.trace("Message sent: " + msg.toString());
-            } catch (Exception e) {
-                reportError(e);
-            }
-        }
+    public Integer asyncFastSend(OFMessage msg) {
+       return asyncFastSend(msg, getNextXid());
+    }
+
+       /**
+        * This method puts the message in an outgoing priority queue with high
+        * priority. It will be served first before normal priority messages. The
+        * method should be used for critical messages such as hello, echo reply
+        * etc. The specified XID is inserted into the message.
+        * 
+        * @param msg The OF message to be sent
+        * @return The XID used
+        */
+    @Override
+    public Integer asyncFastSend(OFMessage msg, int xid) {
+       msg.setXid(xid);
+       transmitQ.add(new PriorityMessage(msg, 1));
         return xid;
     }
 
-    public void resumeSend() {
-        synchronized (outBuffer) {
-            try {
-                outBuffer.flip();
-                socket.write(outBuffer);
-                outBuffer.compact();
-                if (outBuffer.position() > 0) {
-                    this.clientSelectionKey = this.socket.register(
-                            this.selector, SelectionKey.OP_WRITE, this);
-                } else {
-                    this.clientSelectionKey = this.socket.register(
-                            this.selector, SelectionKey.OP_READ, this);
-                }
-            } catch (Exception e) {
-                reportError(e);
-            }
-        }
+   public void resumeSend() {
+        try {
+                       msgReadWriteService.resumeSend();
+               } catch (Exception e) {
+                       reportError(e);
+               }
     }
 
     public void handleMessages() {
-        List<OFMessage> msgs = readMessages();
+        List<OFMessage> msgs = null;
+        
+        try {
+               msgs = msgReadWriteService.readMessages();
+               } catch (Exception e) {
+                       reportError(e);
+               }
+               
         if (msgs == null) {
-            logger.debug(toString() + " is down");
+            logger.debug("{} is down", toString());
             // the connection is down, inform core
             reportSwitchStateChange(false);
             return;
         }
         for (OFMessage msg : msgs) {
-            logger.trace("Message received: " + msg.toString());
+            logger.trace("Message received: {}", msg.toString());
             /*
             if  ((msg.getType() != OFType.ECHO_REQUEST) &&
                        (msg.getType() != OFType.ECHO_REPLY)) {
@@ -293,7 +305,7 @@ public class SwitchHandler implements ISwitch {
                 // send feature request
                 OFMessage featureRequest = factory
                         .getMessage(OFType.FEATURES_REQUEST);
-                asyncSend(featureRequest);
+                asyncFastSend(featureRequest);
                 // delete all pre-existing flows
                 OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
                 OFFlowMod flowMod = (OFFlowMod) factory
@@ -301,14 +313,14 @@ public class SwitchHandler implements ISwitch {
                 flowMod.setMatch(match).setCommand(OFFlowMod.OFPFC_DELETE)
                         .setOutPort(OFPort.OFPP_NONE).setLength(
                                 (short) OFFlowMod.MINIMUM_LENGTH);
-                asyncSend(flowMod);
+                asyncFastSend(flowMod);
                 this.state = SwitchState.WAIT_FEATURES_REPLY;
                 startSwitchTimer();
                 break;
             case ECHO_REQUEST:
                 OFEchoReply echoReply = (OFEchoReply) factory
                         .getMessage(OFType.ECHO_REPLY);
-                asyncSend(echoReply);
+                asyncFastSend(echoReply);
                 break;
             case ECHO_REPLY:
                 this.probeSent = false;
@@ -362,28 +374,6 @@ public class SwitchHandler implements ISwitch {
 
     }
 
-    private List<OFMessage> readMessages() {
-        List<OFMessage> msgs = null;
-        int bytesRead;
-        try {
-            bytesRead = socket.read(inBuffer);
-        } catch (Exception e) {
-            reportError(e);
-            return null;
-        }
-        if (bytesRead == -1) {
-            return null;
-        }
-        inBuffer.flip();
-        msgs = factory.parseMessages(inBuffer);
-        if (inBuffer.hasRemaining()) {
-            inBuffer.compact();
-        } else {
-            inBuffer.clear();
-        }
-        return msgs;
-    }
-
     private void startSwitchTimer() {
         this.periodicTimer = new Timer();
         this.periodicTimer.scheduleAtFixedRate(new TimerTask() {
@@ -394,8 +384,7 @@ public class SwitchHandler implements ISwitch {
                     if ((now - lastMsgReceivedTimeStamp) > SWITCH_LIVENESS_TIMEOUT) {
                         if (probeSent) {
                             // switch failed to respond to our probe, consider it down
-                            logger.warn(toString()
-                                    + " is idle for too long, disconnect");
+                            logger.warn("{} is idle for too long, disconnect", toString());
                             reportSwitchStateChange(false);
                         } else {
                             // send a probe to see if the switch is still alive
@@ -403,14 +392,14 @@ public class SwitchHandler implements ISwitch {
                             probeSent = true;
                             OFMessage echo = factory
                                     .getMessage(OFType.ECHO_REQUEST);
-                            asyncSend(echo);
+                            asyncFastSend(echo);
                         }
                     } else {
                         if (state == SwitchState.WAIT_FEATURES_REPLY) {
                             // send another features request
                             OFMessage request = factory
                                     .getMessage(OFType.FEATURES_REQUEST);
-                            asyncSend(request);
+                            asyncFastSend(request);
                         } else {
                             if (state == SwitchState.WAIT_CONFIG_REPLY) {
                                 //  send another config request
@@ -418,10 +407,10 @@ public class SwitchHandler implements ISwitch {
                                         .getMessage(OFType.SET_CONFIG);
                                 config.setMissSendLength((short) 0xffff)
                                         .setLengthU(OFSetConfig.MINIMUM_LENGTH);
-                                asyncSend(config);
+                                asyncFastSend(config);
                                 OFMessage getConfig = factory
                                         .getMessage(OFType.GET_CONFIG_REQUEST);
-                                asyncSend(getConfig);
+                                asyncFastSend(getConfig);
                             }
                         }
                     }
@@ -439,8 +428,8 @@ public class SwitchHandler implements ISwitch {
     }
 
     private void reportError(Exception e) {
-        //logger.error(toString() + " caught Error " + e.toString());
-        // notify core of this error event
+        logger.debug("Caught exception ", e);
+        // notify core of this error event and disconnect the switch
         ((Controller) core).takeSwitchEventError(this);
     }
 
@@ -473,10 +462,10 @@ public class SwitchHandler implements ISwitch {
                     .getMessage(OFType.SET_CONFIG);
             config.setMissSendLength((short) 0xffff).setLengthU(
                     OFSetConfig.MINIMUM_LENGTH);
-            asyncSend(config);
+            asyncFastSend(config);
             // send config request to make sure the switch can handle the set config
             OFMessage getConfig = factory.getMessage(OFType.GET_CONFIG_REQUEST);
-            asyncSend(getConfig);
+            asyncFastSend(getConfig);
             this.state = SwitchState.WAIT_CONFIG_REPLY;
             // inform core that a new switch is now operational
             reportSwitchStateChange(true);
@@ -545,8 +534,7 @@ public class SwitchHandler implements ISwitch {
                     .get(MESSAGE_RESPONSE_TIMER, TimeUnit.MILLISECONDS);
             return result;
         } catch (Exception e) {
-            logger.warn("Timeout while waiting for " + req.getType()
-                    + " replies");
+            logger.warn("Timeout while waiting for {} replies", req.getType());
             result = null; // to indicate timeout has occurred
             return result;
         }
@@ -573,13 +561,12 @@ public class SwitchHandler implements ISwitch {
             } else {
                 // if result  is not null, this means the switch can't handle this message
                 // the result if OFError already
-                logger.debug("Send " + msg.getType().toString()
-                        + " failed --> " + ((OFError) result).toString());
+                logger.debug("Send {} failed --> {}", 
+                               msg.getType().toString(), ((OFError) result).toString());
             }
             return result;
         } catch (Exception e) {
-            logger.warn("Timeout while waiting for " + msg.getType().toString()
-                    + " reply");
+            logger.warn("Timeout while waiting for {} reply", msg.getType().toString());
             // convert the result into a Boolean with value false
             status = false;
             result = status;
@@ -637,7 +624,7 @@ public class SwitchHandler implements ISwitch {
             worker.wakeup();
         }
     }
-
+    
     @Override
     public Map<Short, OFPhysicalPort> getPhysicalPorts() {
         return this.physicalPorts;
@@ -715,4 +702,65 @@ public class SwitchHandler implements ISwitch {
         }
         return result;
     }
+
+       /*
+        * Transmit thread polls the message out of the priority queue and invokes
+        * messaging service to transmit it over the socket channel
+        */
+    class PriorityMessageTransmit implements Runnable {
+        public void run() {
+            while (true) {
+               try {
+                       if (!transmitQ.isEmpty()) {
+                               PriorityMessage pmsg = transmitQ.poll();
+                               msgReadWriteService.asyncSend(pmsg.msg);
+                               logger.trace("Message sent: {}", pmsg.toString());
+                       }
+                       Thread.sleep(10);
+               } catch (Exception e) {
+                       reportError(e);
+               }
+            }
+        }
+    }
+
+    /*
+     * Setup and start the transmit thread
+     */
+    private void startTransmitThread() {       
+        this.transmitQ = new PriorityBlockingQueue<PriorityMessage>(11, 
+                               new Comparator<PriorityMessage>() {
+                                       public int compare(PriorityMessage p1, PriorityMessage p2) {
+                                               return p2.priority - p1.priority;
+                                       }
+                               });
+        this.transmitThread = new Thread(new PriorityMessageTransmit());
+        this.transmitThread.start();
+    }
+    
+    /*
+     * Setup communication services
+     */
+    private void setupCommChannel() throws Exception {
+        this.selector = SelectorProvider.provider().openSelector();
+        this.socket.configureBlocking(false);
+        this.socket.socket().setTcpNoDelay(true);        
+        this.msgReadWriteService = getMessageReadWriteService();
+    }
+
+    private void sendFirstHello() {
+       try {
+               OFMessage msg = factory.getMessage(OFType.HELLO);
+               asyncFastSend(msg);
+       } catch (Exception e) {
+               reportError(e);
+       }
+    }
+    
+    private IMessageReadWrite getMessageReadWriteService() throws Exception {
+       String str = System.getProperty("secureChannelEnabled");
+        return ((str != null) && (str.equalsIgnoreCase("true"))) ? 
+                       new SecureMessageReadWriteService(socket, selector) : 
+                       new MessageReadWriteService(socket, selector);
+    }
 }
index 2ee1583af7ebebe7f089f2992220f69e25338ade..3cd696854c3c9d89a6f6d5543b3ce276f751dfbc 100644 (file)
@@ -84,7 +84,7 @@ public class Activator extends ComponentActivatorAbstractBase {
             // provider of service exists
             c.add(createContainerServiceDependency(containerName).setService(
                     IListenRoutingUpdates.class).setCallbacks(
-                    "setLIstenRoutingUpdates", "unsetLIstenRoutingUpdates")
+                    "setListenRoutingUpdates", "unsetListenRoutingUpdates")
                     .setRequired(false));
 
             c.add(createContainerServiceDependency(containerName).setService(
index 6f1dc3f9d707bd49016a67005ef88799349bd64f..05ec5d40530919941dd69f67a197111c7a565687 100644 (file)
@@ -71,7 +71,7 @@ public class DijkstraImplementation implements IRouting, ITopologyManagerAware {
         }
     }
 
-    public void unsetRoutingUpdates(IListenRoutingUpdates i) {
+    public void unsetListenRoutingUpdates(IListenRoutingUpdates i) {
         if (this.routingAware == null) {
             return;
         }
diff --git a/opendaylight/routing/dijkstra_implementation/src/main/resources/OSGI-INF/component-factory.xml b/opendaylight/routing/dijkstra_implementation/src/main/resources/OSGI-INF/component-factory.xml
deleted file mode 100644 (file)
index d71bef8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
- activate="factoryStartUp" deactivate="factoryShutDown"
- factory="routing.dijkstra_implementation.factory" name="routing.dijkstra_implementation.ComponentFactory">
-   <implementation class="org.opendaylight.controller.routing.dijkstra_implementation.internal.DijkstraImplementation"/>
-   <service>
-      <provide interface="org.osgi.service.component.ComponentFactory"/>
-   </service>
-</scr:component>
diff --git a/opendaylight/routing/dijkstra_implementation/src/main/resources/OSGI-INF/component.xml b/opendaylight/routing/dijkstra_implementation/src/main/resources/OSGI-INF/component.xml
deleted file mode 100644 (file)
index 4f9cdc8..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
-               activate="startUp"
-               deactivate="shutDown"
-               name="routing.dijkstra_implementation.Component">
-  <implementation class="org.opendaylight.controller.routing.dijkstra_implementation.internal.DijkstraImplementation"/>
-
-  <service>
-    <provide interface="org.opendaylight.controller.sal.routing.IRouting"/>
-    <provide interface="org.opendaylight.controller.topologymanager.ITopologyManagerAware"/>
-  </service>
-  <reference name="IListenRoutingUpdates"
-             bind="setListenRoutingUpdates"
-             unbind="unsetRoutingUpdates"
-             cardinality="0..n"
-             policy="dynamic"
-             interface="org.opendaylight.controller.sal.routing.IListenRoutingUpdates"/>
-</scr:component>
index add22412cbc9241b651701bcdbe77d134fd28292..17aa745ec0d2c2f7457066bd3b5cbcfd242dcdb9 100644 (file)
@@ -23,6 +23,9 @@
         <module>binding-generator-util</module>\r
         <module>binding-generator-impl</module>\r
         <module>binding-java-api-generator</module>\r
+        <module>yang-to-sources</module>\r
+        <module>yang-to-sources-plugin</module>\r
+        <module>yang-to-sources-plugin-it</module>\r
     </modules>\r
     <dependencies>\r
 \r
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/.gitignore b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/.gitignore
new file mode 100644 (file)
index 0000000..6bd6746
--- /dev/null
@@ -0,0 +1 @@
+log.txt
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/pom.xml
new file mode 100644 (file)
index 0000000..63a743d
--- /dev/null
@@ -0,0 +1,20 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>yang-to-sources-plugin-it</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-verifier</artifactId>
+            <version>1.4</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/CombineTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/CombineTest.java
new file mode 100644 (file)
index 0000000..7171ee9
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.yang2sources.plugin.it;
+
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.it.Verifier;
+import org.junit.Test;
+
+public class CombineTest {
+
+    @Test
+    public void testCorrect() throws VerificationException {
+        Verifier v = YangToSourcesPluginTest.setUp("Correct_combined/", false);
+        YangToResourcesPluginTest.verifyCorrectLog(v);
+        YangToSourcesPluginTest.verifyCorrectLog(v);
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToResourcesPluginTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToResourcesPluginTest.java
new file mode 100644 (file)
index 0000000..f7aa4f7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.yang2sources.plugin.it;
+
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.it.Verifier;
+import org.junit.Test;
+
+public class YangToResourcesPluginTest {
+
+    @Test
+    public void testCorrect() throws VerificationException {
+        Verifier v = YangToSourcesPluginTest.setUp("Correct_resources/", false);
+        verifyCorrectLog(v);
+    }
+
+    static void verifyCorrectLog(Verifier v) throws VerificationException {
+        v.verifyErrorFreeLog();
+        v.verifyTextInLog("[INFO] yang-to-resources: Resource provider instantiated from org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-resources: Resource provider org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl call successful");
+    }
+
+    @Test
+    public void testNoGenerators() throws VerificationException {
+        Verifier v = YangToSourcesPluginTest.setUp("NoGenerators_resources/",
+                false);
+        v.verifyErrorFreeLog();
+        v.verifyTextInLog("[WARNING] yang-to-resources: No resource provider classes provided");
+    }
+
+    @Test
+    public void testUnknownGenerator() throws VerificationException {
+        Verifier v = YangToSourcesPluginTest.setUp(
+                "UnknownGenerator_resources/", true);
+        v.verifyTextInLog("[ERROR] yang-to-resources: Unable to provide resources with unknown resource provider");
+        v.verifyTextInLog("java.lang.ClassNotFoundException: unknown");
+        v.verifyTextInLog("[INFO] yang-to-resources: Resource provider instantiated from org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-resources: Resource provider org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl call successful");
+        v.verifyTextInLog("[ERROR] yang-to-resources: One or more code resource provider failed, including failed list(resourceProviderClass=exception) {unknown=java.lang.ClassNotFoundException}");
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTest.java
new file mode 100644 (file)
index 0000000..1d8f570
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.yang2sources.plugin.it;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+import java.io.File;
+
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.it.Verifier;
+import org.junit.Test;
+
+public class YangToSourcesPluginTest {
+
+    @Test
+    public void testYangRootNotExist() {
+        try {
+            setUp("YangRootNotExist/", false);
+        } catch (VerificationException e) {
+            assertVerificationException(e,
+                    "[ERROR] yang-to-sources: Unable to parse yang files from unknown");
+            assertVerificationException(
+                    e,
+                    "Caused by: org.apache.maven.plugin.MojoExecutionException: yang-to-sources: Unable to parse yang files from unknown");
+            return;
+        }
+
+        fail("Verification exception should have been thrown");
+    }
+
+    @Test
+    public void testCorrect() throws VerificationException {
+        Verifier v = setUp("Correct/", false);
+        verifyCorrectLog(v);
+    }
+
+    static void verifyCorrectLog(Verifier v) throws VerificationException {
+        v.verifyErrorFreeLog();
+        v.verifyTextInLog("[INFO] yang-to-sources: yang files parsed from");
+        v.verifyTextInLog("[INFO] yang-to-sources: Code generator instantiated from org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-sources: Sources generated by org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: null");
+    }
+
+    @Test
+    public void testNoGenerators() throws VerificationException {
+        Verifier v = setUp("NoGenerators/", false);
+        v.verifyErrorFreeLog();
+        v.verifyTextInLog("[WARNING] yang-to-sources: No code generators provided");
+    }
+
+    @Test
+    public void testUnknownGenerator() throws VerificationException {
+        Verifier v = setUp("UnknownGenerator/", true);
+        v.verifyTextInLog("[ERROR] yang-to-sources: Unable to generate sources with unknown generator");
+        v.verifyTextInLog("java.lang.ClassNotFoundException: unknown");
+        v.verifyTextInLog("[INFO] yang-to-sources: Code generator instantiated from org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-sources: Sources generated by org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: null");
+        v.verifyTextInLog("[ERROR] yang-to-sources: One or more code generators failed, including failed list(generatorClass=exception) {unknown=java.lang.ClassNotFoundException}");
+    }
+
+    @Test
+    public void testNoYangFiles() throws VerificationException {
+        Verifier v = setUp("NoYangFiles/", false);
+        v.verifyTextInLog("[WARNING] yang-to-sources: No yang file found in ");
+        v.verifyTextInLog("[INFO] yang-to-sources: yang files parsed from []");
+        v.verifyTextInLog("[INFO] yang-to-sources: Code generator instantiated from org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-sources: Sources generated by org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: null");
+    }
+
+    static void assertVerificationException(VerificationException e,
+            String string) {
+        assertThat(e.getMessage(), containsString(string));
+    }
+
+    static Verifier setUp(String project, boolean ignoreF)
+            throws VerificationException {
+        Verifier verifier = new Verifier(new File("src/test/resources/"
+                + project).getAbsolutePath());
+        if (ignoreF)
+            verifier.addCliOption("-fn");
+        verifier.executeGoal("generate-resources");
+        return verifier;
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/pom.xml
new file mode 100644 (file)
index 0000000..d94afbd
--- /dev/null
@@ -0,0 +1,49 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-to-sources</artifactId>
+                        <version>1.0</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/resources/model/testfile1.yang b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/resources/model/testfile1.yang
new file mode 100644 (file)
index 0000000..ba0c15e
--- /dev/null
@@ -0,0 +1,57 @@
+module types1 {
+       yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+    
+    import types2 {
+         prefix "data";
+         revision-date 2013-02-27;
+     }
+    
+    organization "Cisco";
+    contact "WILL-BE-DEFINED-LATER";
+    
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+    
+    container interfaces {
+         list ifEntry {
+             key "ifIndex";
+
+             leaf ifIndex {
+                 type uint32;
+                 units minutes;
+             }
+             
+             leaf ifMtu {
+                 type int32;
+             }
+         }
+     }
+     
+       leaf testleaf {
+               type data:my-base-int32-type {
+                       range "min..max";
+               }
+       }
+       
+       leaf test-string-leaf {
+               type data:my-string-type-ext;
+       }
+       
+       leaf test-int-leaf {
+               type data:my-int-type-ext;
+       }
+       
+       leaf test-decimal-leaf {
+               type data:my-decimal-type {
+                       fraction-digits 4;
+               }
+       }
+       
+       leaf test-decimal-leaf2 {
+               type data:my-decimal-type-ext;
+       }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/resources/model/testfile2.yang b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct/resources/model/testfile2.yang
new file mode 100644 (file)
index 0000000..3e9da52
--- /dev/null
@@ -0,0 +1,100 @@
+module types2 {
+       yang-version 1;
+    namespace "urn:simple.types.data.demo";
+    prefix "t2";
+    
+    import types1 {
+         prefix "if";
+         revision-date 2013-02-27;
+     }
+
+    organization "Cisco";
+    contact "WILL-BE-DEFINED-LATER";
+    description "This is types-data test description";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+    
+    typedef my-base-int32-type {
+               type int32 {
+               range "2..20";
+        }
+       }
+
+     typedef my-type1 {
+       type my-base-int32-type {
+               range "11..max";
+       }
+       }
+       
+       typedef my-string-type {
+               type string {
+                       pattern "[a-k]*";
+               }
+       }
+       
+       typedef my-string-type2 {
+               type my-string-type {
+                       pattern "[b-u]*";
+               }
+       }
+       
+       typedef my-string-type-ext {
+               type my-string-type2 {
+                       pattern "[e-z]*";
+               }
+       }
+       
+       typedef my-int-type {
+               type int32 {
+                       range "10..20";
+               }
+       }
+       
+       typedef my-int-type2 {
+               type my-int-type {
+                       range "12..18";
+               }
+       }
+       
+       typedef my-int-type-ext {
+               type my-int-type2 {
+                       range "14..16";
+               }
+       }
+       
+       typedef my-decimal-type {
+               type decimal64 {
+                       fraction-digits 6;
+               }
+       }
+       
+       typedef my-decimal-type-ext {
+               type decimal64 {
+                       fraction-digits 5;
+               }
+       }
+
+    augment "/if:interfaces/if:ifEntry" {
+       when "if:ifType='ds0'";
+        leaf ds0ChannelNumber {
+               type string;
+        }
+       }
+
+    leaf if-name {
+       type leafref {
+               path "/interface/name";
+        }
+    }
+     
+    leaf name {
+       type string;
+    }
+     
+       leaf nested-type-leaf {
+               type my-type1;
+       }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct_combined/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct_combined/pom.xml
new file mode 100644 (file)
index 0000000..9080f35
--- /dev/null
@@ -0,0 +1,60 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                            <goal>generate-resources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        outDir/src
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <resourceProviders>
+                                <provider>
+                                    <resourceProviderClass>
+                                        org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl
+                                    </resourceProviderClass>
+                                    <outputBaseDir>
+                                        outDir/resources
+                                    </outputBaseDir>
+                                </provider>
+                            </resourceProviders>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-to-sources</artifactId>
+                        <version>1.0</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct_resources/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/Correct_resources/pom.xml
new file mode 100644 (file)
index 0000000..4456fcf
--- /dev/null
@@ -0,0 +1,49 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-resources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <resourceProviders>
+                                <provider>
+                                    <resourceProviderClass>
+                                        org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl
+                                    </resourceProviderClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </provider>
+                            </resourceProviders>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-to-sources</artifactId>
+                        <version>1.0</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoGenerators/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoGenerators/pom.xml
new file mode 100644 (file)
index 0000000..f194e9d
--- /dev/null
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <codeGenerators>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoGenerators_resources/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoGenerators_resources/pom.xml
new file mode 100644 (file)
index 0000000..0861ca2
--- /dev/null
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-resources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <resourceProviders>
+                            </resourceProviders>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoYangFiles/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/NoYangFiles/pom.xml
new file mode 100644 (file)
index 0000000..4cce379
--- /dev/null
@@ -0,0 +1,49 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-to-sources</artifactId>
+                        <version>1.0</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/UnknownGenerator/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/UnknownGenerator/pom.xml
new file mode 100644 (file)
index 0000000..0a1afad
--- /dev/null
@@ -0,0 +1,57 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        unknown
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-to-sources</artifactId>
+                        <version>1.0</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml
new file mode 100644 (file)
index 0000000..df03f95
--- /dev/null
@@ -0,0 +1,57 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-resources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <resourceProviders>
+                                <provider>
+                                    <resourceProviderClass>
+                                        org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl
+                                    </resourceProviderClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </provider>
+                                <provider>
+                                    <resourceProviderClass>
+                                        unknown
+                                    </resourceProviderClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </provider>
+                            </resourceProviders>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-to-sources</artifactId>
+                        <version>1.0</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/YangRootNotExist/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin-it/src/test/resources/YangRootNotExist/pom.xml
new file mode 100644 (file)
index 0000000..3ab27e5
--- /dev/null
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-to-sources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>unknown</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/pom.xml
new file mode 100644 (file)
index 0000000..a2d3a22
--- /dev/null
@@ -0,0 +1,79 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>yang-to-sources-plugin</artifactId>
+    <packaging>maven-plugin</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.0.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <version>3.2</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-parser-impl</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-to-sources</artifactId>
+            <version>1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-to-sources</artifactId>
+            <version>1.0</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.8.4</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>3.2</version>
+                <configuration>
+                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>mojo-descriptor</id>
+                        <goals>
+                            <goal>descriptor</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java
new file mode 100644 (file)
index 0000000..f6602e6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.yang2sources.plugin;
+
+import java.io.File;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Complex configuration arguments
+ */
+public abstract class ConfigArg {
+
+    protected File outputBaseDir;
+
+    public ConfigArg(File outputBaseDir) {
+        this.outputBaseDir = outputBaseDir;
+    }
+
+    public ConfigArg() {
+    }
+
+    public File getOutputBaseDir() {
+        return outputBaseDir;
+    }
+
+    public abstract void check();
+
+    public static final class ResourceProviderArg extends ConfigArg {
+        private String resourceProviderClass;
+
+        public ResourceProviderArg() {
+        }
+
+        public ResourceProviderArg(String resourceProviderClass,
+                File outputBaseDir) {
+            super(outputBaseDir);
+            this.resourceProviderClass = resourceProviderClass;
+        }
+
+        @Override
+        public void check() {
+            Preconditions
+                    .checkNotNull(resourceProviderClass,
+                            "resourceProviderClass for ResourceProvider cannot be null");
+            Preconditions.checkNotNull(outputBaseDir,
+                    "outputBaseDir for ResourceProvider cannot be null, "
+                            + resourceProviderClass);
+        }
+
+        public String getResourceProviderClass() {
+            return resourceProviderClass;
+        }
+    }
+
+    /**
+     * Transfer object for code generator class and output directory.
+     */
+    public static final class CodeGeneratorArg extends ConfigArg {
+        private String codeGeneratorClass;
+
+        public CodeGeneratorArg() {
+        }
+
+        public CodeGeneratorArg(String codeGeneratorClass, File outputBaseDir) {
+            super(outputBaseDir);
+            this.codeGeneratorClass = codeGeneratorClass;
+        }
+
+        @Override
+        public void check() {
+            Preconditions.checkNotNull(codeGeneratorClass,
+                    "codeGeneratorClass for CodeGenerator cannot be null");
+            Preconditions.checkNotNull(outputBaseDir,
+                    "outputBaseDir for CodeGenerator cannot be null, "
+                            + codeGeneratorClass);
+        }
+
+        public String getCodeGeneratorClass() {
+            return codeGeneratorClass;
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java
new file mode 100644 (file)
index 0000000..98a5d85
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.yang2sources.plugin;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Maps;
+
+final class Util {
+
+    static final String YANG_SUFFIX = "yang";
+
+    // Cache for listed directories and found yang files. Typically yang files
+    // are utilized twice. First: code is generated during generate-sources
+    // phase Second: yang files are copied as resources during
+    // generate-resources phase. This cache ensures that yang files are listed
+    // only once.
+    private static Map<String, Collection<File>> cache = Maps
+            .newHashMapWithExpectedSize(10);
+
+    /**
+     * List files recursively and return as array of String paths. Use cache of
+     * size 1.
+     */
+    static Collection<File> listFiles(String rootDir) {
+
+        if (cache.get(rootDir) != null)
+            return cache.get(rootDir);
+
+        Collection<File> yangFiles = FileUtils.listFiles(new File(rootDir),
+                new String[] { YANG_SUFFIX }, true);
+
+        toCache(rootDir, yangFiles);
+        return yangFiles;
+    }
+
+    static String[] listFilesAsArrayOfPaths(String rootDir) {
+        String[] filesArray = new String[] {};
+        Collection<File> yangFiles = listFiles(rootDir);
+
+        // If collection is empty, return empty array [] rather then [null]
+        // array, that is created by default
+        return yangFiles.isEmpty() ? filesArray : Collections2.transform(
+                yangFiles, new Function<File, String>() {
+
+                    @Override
+                    public String apply(File input) {
+                        return input.getPath();
+                    }
+                }).toArray(filesArray);
+    }
+
+    private static void toCache(final String rootDir,
+            final Collection<File> yangFiles) {
+        cache.put(rootDir, yangFiles);
+    }
+
+    /**
+     * Instantiate object from fully qualified class name
+     */
+    static <T> T getInstance(String codeGeneratorClass, Class<T> baseType)
+            throws ClassNotFoundException, InstantiationException,
+            IllegalAccessException {
+        return baseType.cast(resolveClass(codeGeneratorClass, baseType)
+                .newInstance());
+    }
+
+    private static Class<?> resolveClass(String codeGeneratorClass,
+            Class<?> baseType) throws ClassNotFoundException {
+        Class<?> clazz = Class.forName(codeGeneratorClass);
+
+        if (!isImplemented(baseType, clazz))
+            throw new IllegalArgumentException("Code generator " + clazz
+                    + " has to implement " + baseType);
+        return clazz;
+    }
+
+    private static boolean isImplemented(Class<?> expectedIface,
+            Class<?> byClazz) {
+        for (Class<?> iface : byClazz.getInterfaces()) {
+            if (iface.equals(expectedIface))
+                return true;
+        }
+        return false;
+    }
+
+    static String message(String message, String logPrefix, Object... args) {
+        String innerMessage = String.format(message, args);
+        return String.format("%s %s", logPrefix, innerMessage);
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java
new file mode 100644 (file)
index 0000000..7bb49dc
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.yang2sources.plugin;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.ResourceProviderArg;
+import org.opendaylight.controller.yang2sources.spi.ResourceGenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
+@Mojo(name = "generate-resources", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
+public final class YangToResourcesMojo extends AbstractMojo {
+
+    private static final String LOG_PREFIX = "yang-to-resources:";
+
+    @Parameter(required = true)
+    private ResourceProviderArg[] resourceProviders;
+
+    @Parameter(required = true)
+    private String yangFilesRootDir;
+
+    @VisibleForTesting
+    YangToResourcesMojo(ResourceProviderArg[] resourceProviderArgs,
+            String yangFilesRootDir) {
+        super();
+        this.resourceProviders = resourceProviderArgs;
+        this.yangFilesRootDir = yangFilesRootDir;
+    }
+
+    public YangToResourcesMojo() {
+        super();
+    }
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+
+        if (resourceProviders.length == 0) {
+            getLog().warn(
+                    Util.message("No resource provider classes provided",
+                            LOG_PREFIX));
+            return;
+        }
+
+        Map<String, String> thrown = Maps.newHashMap();
+        Collection<File> yangFiles = Util.listFiles(yangFilesRootDir);
+
+        for (ResourceProviderArg resourceProvider : resourceProviders) {
+            try {
+
+                provideResourcesWithOneProvider(yangFiles, resourceProvider);
+
+            } catch (Exception e) {
+                // try other generators, exception will be thrown after
+                getLog().error(
+                        Util.message(
+                                "Unable to provide resources with %s resource provider",
+                                LOG_PREFIX,
+                                resourceProvider.getResourceProviderClass()), e);
+                thrown.put(resourceProvider.getResourceProviderClass(), e
+                        .getClass().getCanonicalName());
+            }
+        }
+
+        if (!thrown.isEmpty()) {
+            String message = Util
+                    .message(
+                            "One or more code resource provider failed, including failed list(resourceProviderClass=exception) %s",
+                            LOG_PREFIX, thrown.toString());
+            getLog().error(message);
+            throw new MojoFailureException(message);
+        }
+    }
+
+    /**
+     * Instantiate provider from class and call required method
+     */
+    private void provideResourcesWithOneProvider(Collection<File> yangFiles,
+            ResourceProviderArg resourceProvider)
+            throws ClassNotFoundException, InstantiationException,
+            IllegalAccessException {
+
+        resourceProvider.check();
+
+        ResourceGenerator g = Util.getInstance(
+                resourceProvider.getResourceProviderClass(),
+                ResourceGenerator.class);
+        getLog().info(
+                Util.message("Resource provider instantiated from %s",
+                        LOG_PREFIX, resourceProvider.getResourceProviderClass()));
+
+        g.generateResourceFiles(yangFiles, resourceProvider.getOutputBaseDir());
+        getLog().info(
+                Util.message("Resource provider %s call successful",
+                        LOG_PREFIX, resourceProvider.getResourceProviderClass()));
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java
new file mode 100644 (file)
index 0000000..2928298
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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.yang2sources.plugin;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
+import org.opendaylight.controller.yang.model.parser.impl.YangModelParserImpl;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
+import org.opendaylight.controller.yang2sources.spi.CodeGenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
+@Mojo(name = "generate-sources", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
+public final class YangToSourcesMojo extends AbstractMojo {
+
+    private static final String LOG_PREFIX = "yang-to-sources:";
+
+    @Parameter(required = true)
+    private CodeGeneratorArg[] codeGenerators;
+
+    @Parameter(required = true)
+    private String yangFilesRootDir;
+
+    private final YangModelParser parser;
+
+    @VisibleForTesting
+    YangToSourcesMojo(CodeGeneratorArg[] codeGeneratorArgs,
+            YangModelParser parser, String yangFilesRootDir) {
+        super();
+        this.codeGenerators = codeGeneratorArgs;
+        this.yangFilesRootDir = yangFilesRootDir;
+        this.parser = parser;
+    }
+
+    public YangToSourcesMojo() {
+        super();
+        parser = new YangModelParserImpl();
+    }
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        SchemaContext context = processYang();
+        generateSources(context);
+    }
+
+    /**
+     * Generate {@link SchemaContext} with {@link YangModelParserImpl}
+     */
+    private SchemaContext processYang() throws MojoExecutionException {
+        try {
+            String[] yangFiles = Util.listFilesAsArrayOfPaths(yangFilesRootDir);
+
+            if (yangFiles.length == 0)
+                getLog().warn(
+                        Util.message("No %s file found in %s", LOG_PREFIX,
+                                Util.YANG_SUFFIX, yangFilesRootDir));
+            // TODO only warning or throw exception ?
+
+            Set<Module> parsedYang = parser.parseYangModels(yangFiles);
+            SchemaContext resolveSchemaContext = parser
+                    .resolveSchemaContext(parsedYang);
+            getLog().info(
+                    Util.message("%s files parsed from %s", LOG_PREFIX,
+                            Util.YANG_SUFFIX, Arrays.toString(yangFiles)));
+            return resolveSchemaContext;
+
+            // MojoExecutionException is thrown since execution cannot continue
+        } catch (Exception e) {
+            String message = Util.message("Unable to parse %s files from %s",
+                    LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir);
+            getLog().error(message, e);
+            throw new MojoExecutionException(message, e);
+        }
+    }
+
+    /**
+     * Call generate on every generator from plugin configuration
+     */
+    private void generateSources(SchemaContext context)
+            throws MojoFailureException {
+        if (codeGenerators.length == 0) {
+            getLog().warn(
+                    Util.message("No code generators provided", LOG_PREFIX));
+            return;
+        }
+
+        Map<String, String> thrown = Maps.newHashMap();
+
+        for (CodeGeneratorArg codeGenerator : codeGenerators) {
+            try {
+
+                generateSourcesWithOneGenerator(context, codeGenerator);
+
+            } catch (Exception e) {
+                // try other generators, exception will be thrown after
+                getLog().error(
+                        Util.message(
+                                "Unable to generate sources with %s generator",
+                                LOG_PREFIX,
+                                codeGenerator.getCodeGeneratorClass()), e);
+                thrown.put(codeGenerator.getCodeGeneratorClass(), e.getClass()
+                        .getCanonicalName());
+            }
+        }
+
+        if (!thrown.isEmpty()) {
+            String message = Util
+                    .message(
+                            "One or more code generators failed, including failed list(generatorClass=exception) %s",
+                            LOG_PREFIX, thrown.toString());
+            getLog().error(message);
+            throw new MojoFailureException(message);
+        }
+    }
+
+    /**
+     * Instantiate generator from class and call required method
+     */
+    private void generateSourcesWithOneGenerator(SchemaContext context,
+            CodeGeneratorArg codeGenerator) throws ClassNotFoundException,
+            InstantiationException, IllegalAccessException {
+
+        codeGenerator.check();
+
+        CodeGenerator g = Util.getInstance(
+                codeGenerator.getCodeGeneratorClass(), CodeGenerator.class);
+        getLog().info(
+                Util.message("Code generator instantiated from %s", LOG_PREFIX,
+                        codeGenerator.getCodeGeneratorClass()));
+
+        Collection<File> generated = g.generateSources(context,
+                codeGenerator.getOutputBaseDir());
+        getLog().info(
+                Util.message("Sources generated by %s: %s", LOG_PREFIX,
+                        codeGenerator.getCodeGeneratorClass(), generated));
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateResourcesTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateResourcesTest.java
new file mode 100644 (file)
index 0000000..a23e3b5
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.yang2sources.plugin;
+
+import static org.hamcrest.core.Is.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.ResourceProviderArg;
+import org.opendaylight.controller.yang2sources.spi.ResourceGenerator;
+
+public class GenerateResourcesTest {
+
+    private String yang;
+    private YangToResourcesMojo mojo;
+    private File outDir;
+
+    @Before
+    public void setUp() {
+        yang = new File(getClass().getResource("/mock.yang").getFile())
+                .getParent();
+        outDir = new File("outputDir");
+        mojo = new YangToResourcesMojo(
+                new ResourceProviderArg[] {
+                        new ResourceProviderArg(ProviderMock.class.getName(),
+                                outDir),
+                        new ResourceProviderArg(ProviderMock2.class.getName(),
+                                outDir) }, yang);
+    }
+
+    @Test
+    public void test() throws Exception {
+        mojo.execute();
+        assertThat(ProviderMock.called, is(1));
+        assertThat(ProviderMock2.called, is(1));
+        assertThat(ProviderMock2.baseDir, is(outDir));
+        assertThat(ProviderMock.baseDir, is(outDir));
+    }
+
+    public static class ProviderMock implements ResourceGenerator {
+
+        private static int called = 0;
+        private static File baseDir;
+
+        @Override
+        public void generateResourceFiles(Collection<File> resources,
+                File outputDir) {
+            called++;
+            baseDir = outputDir;
+        }
+    }
+
+    public static class ProviderMock2 implements ResourceGenerator {
+
+        private static int called = 0;
+        private static File baseDir;
+
+        @Override
+        public void generateResourceFiles(Collection<File> resources,
+                File outputDir) {
+            called++;
+            baseDir = outputDir;
+        }
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java
new file mode 100644 (file)
index 0000000..be19db1
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.yang2sources.plugin;
+
+import static org.hamcrest.core.Is.*;
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import java.io.File;
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
+import org.opendaylight.controller.yang2sources.spi.CodeGenerator;
+
+import com.google.common.collect.Lists;
+
+public class GenerateSourcesTest {
+
+    @Mock
+    private YangModelParser parser;
+    private String yang;
+    private YangToSourcesMojo mojo;
+    private File outDir;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        yang = new File(getClass().getResource("/mock.yang").getFile())
+                .getParent();
+        outDir = new File("outputDir");
+        mojo = new YangToSourcesMojo(
+                new CodeGeneratorArg[] { new CodeGeneratorArg(
+                        GeneratorMock.class.getName(), outDir) }, parser, yang);
+    }
+
+    @Test
+    public void test() throws Exception {
+        mojo.execute();
+        verify(parser, times(1)).parseYangModels((String[]) anyVararg());
+        assertThat(GeneratorMock.called, is(1));
+        assertThat(GeneratorMock.outputDir, is(outDir));
+    }
+
+    public static class GeneratorMock implements CodeGenerator {
+
+        private static int called = 0;
+        private static File outputDir;
+
+        @Override
+        public Collection<File> generateSources(SchemaContext context,
+                File baseDir) {
+            called++;
+            outputDir = baseDir;
+            return Lists.newArrayList();
+        }
+
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java
new file mode 100644 (file)
index 0000000..0a17d9f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.yang2sources.plugin;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.util.Collection;
+
+import org.junit.Test;
+
+public class UtilTest {
+
+    @Test
+    public void testCache() {
+        String yang = new File(getClass().getResource("/mock.yang").getFile())
+                .getParent();
+        Collection<File> files = Util.listFiles(yang);
+        Collection<File> files2 = Util.listFiles(yang);
+        assertTrue(files == files2);
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/resources/mock.yang b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources-plugin/src/test/resources/mock.yang
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources/pom.xml b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources/pom.xml
new file mode 100644 (file)
index 0000000..c8c74c9
--- /dev/null
@@ -0,0 +1,36 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>1.0</version>
+    </parent>
+    <artifactId>yang-to-sources</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-model-api</artifactId>
+            <version>1.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
@@ -1,16 +1,18 @@
+/*
+ * 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.yang2sources.spi;
 
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.core.impl;\r
-\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-\r
-abstract public class BrokerServiceImpl implements BrokerService {\r
-\r
-    ConsumerSessionImpl session;\r
-}\r
+import java.io.File;
+import java.util.Collection;
+
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+
+public interface CodeGenerator {
+
+    Collection<File> generateSources(SchemaContext context, File outputBaseDir);
+}
@@ -1,10 +1,16 @@
+/*
+ * 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.yang2sources.spi;
 
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
+import java.io.File;
+import java.util.Collection;
 
-package org.opendaylight.controller.sal.core.impl.data;
\ No newline at end of file
+public interface ResourceGenerator {
+
+    void generateResourceFiles(Collection<File> resources, File outputBaseDir);
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java
new file mode 100644 (file)
index 0000000..6683978
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.yang2sources.spi;
+
+import java.io.File;
+import java.util.Collection;
+
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+
+public class CodeGeneratorTestImpl implements CodeGenerator {
+
+    @Override
+    public Collection<File> generateSources(SchemaContext context,
+            File outputBaseDir) {
+        // no-op
+        return null;
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/test/java/org/opendaylight/controller/yang2sources/spi/ResourceProviderTestImpl.java b/opendaylight/sal/yang-prototype/code-generator/yang-to-sources/src/test/java/org/opendaylight/controller/yang2sources/spi/ResourceProviderTestImpl.java
new file mode 100644 (file)
index 0000000..dc52184
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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.yang2sources.spi;
+
+import java.io.File;
+import java.util.Collection;
+
+public class ResourceProviderTestImpl implements ResourceGenerator {
+
+    @Override
+    public void generateResourceFiles(Collection<File> resources,
+            File outputBaseDir) {
+        // no-op
+    }
+
+}
index 1b633b4a25ae78f1cb32710a3c9590921e987fb2..9f77613b89ff584b8304b09d822e8ed3e5cdde6e 100644 (file)
@@ -7,15 +7,15 @@
        <packaging>pom</packaging>\r
 \r
        <modules>\r
+               <module>sal-common</module>\r
+               <module>sal-common-util</module>\r
                <module>sal-core-api</module>\r
                <module>sal-data-api</module>\r
                <module>sal-binding-api</module>\r
                <module>sal-binding-spi</module>\r
                <module>sal-binding-broker-impl</module>\r
                <module>sal-schema-repository-api</module>\r
-               <module>sal-common</module>\r
                <module>sal-core-spi</module>\r
-               <module>../yang</module>\r
                <module>sal-broker-impl</module>\r
                <module>sal-core-demo</module>\r
        </modules>\r
                                <artifactId>slf4j-api</artifactId>\r
                                <version>1.7.2</version>\r
                        </dependency>\r
+                       <dependency>\r
+                               <groupId>junit</groupId>\r
+                               <artifactId>junit</artifactId>\r
+                               <version>4.10</version>\r
+                       </dependency>\r
                </dependencies>\r
        </dependencyManagement>\r
 \r
@@ -40,7 +45,6 @@
                <dependency>\r
                        <groupId>junit</groupId>\r
                        <artifactId>junit</artifactId>\r
-                       <version>4.10</version>\r
                        <scope>test</scope>\r
                        <optional>true</optional>\r
                </dependency>\r
index e4e7be5c6c196cef628d8598d498ad3928cfc3a2..8f90ddbbea8e073056f43d566e4996acf500c48a 100644 (file)
@@ -62,24 +62,6 @@ public interface DataProviderService extends DataBrokerService {
      * @param store\r
      * @param refresher\r
      */\r
-    void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);\r
-\r
-    /**\r
-     * Trigger for refreshing of the data exposed by the {@link Provider}\r
-     * \r
-\r
-     * \r
-     */\r
-    public interface DataRefresher extends\r
-            BindingAwareProvider.ProviderFunctionality {\r
-\r
-        /**\r
-         * Fired when some component explicitly requested the data refresh.\r
-         * \r
-         * The provider which exposed the {@link DataRefresher} should republish\r
-         * its provided data by editing the data in all affected data stores.\r
-         */\r
-        void refreshData();\r
-    }\r
+   void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);\r
 \r
 }\r
index 56b2a9f4dabdb0c675360b8e417d1d2090f1a5db..0f9997651fd677dbb4fb01536278c43252d439c3 100644 (file)
@@ -7,9 +7,20 @@
  */\r
 package org.opendaylight.controller.sal.binding.api;\r
 \r
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;\r
-\r
-public interface DataRefresher extends ProviderFunctionality {\r
+/**\r
+ * Trigger for refreshing of the data exposed by the {@link Provider}\r
+ * \r
+ * \r
+ * \r
+ */\r
+public interface DataRefresher extends\r
+        BindingAwareProvider.ProviderFunctionality {\r
 \r
+    /**\r
+     * Fired when some component explicitly requested the data refresh.\r
+     * \r
+     * The provider which exposed the {@link DataRefresher} should republish its\r
+     * provided data by editing the data in all affected data stores.\r
+     */\r
     void refreshData();\r
-}\r
+}
\ No newline at end of file
index f126744652b78f8a4b87cf14a3b8adf5852c0137..2d427cb61fa5aa6993e4648d83a3c2d27bf3eb2d 100644 (file)
 \r
 \r
        <dependencies>\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>sal-common-util</artifactId>\r
+                       <version>1.0-SNAPSHOT</version>\r
+               </dependency>\r
                <dependency>\r
                        <groupId>org.opendaylight.controller</groupId>\r
                        <artifactId>sal-binding-api</artifactId>\r
index 2209f84cac7ca86b29da96487dd1b45329daca5d..32eff18d4a3644069cec3d8cfce0bbdff7fb5c36 100644 (file)
@@ -7,17 +7,36 @@
  */
 package org.opendaylight.controller.sal.binding.impl;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.controller.sal.binding.spi.Mapper;
+import org.opendaylight.controller.sal.binding.spi.MappingProvider;
+import org.opendaylight.controller.sal.binding.spi.RpcMapper;
+import org.opendaylight.controller.sal.binding.spi.RpcMapper.RpcProxyInvocationHandler;
 import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.yang.binding.DataObject;
 import org.opendaylight.controller.yang.binding.RpcService;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.common.RpcResult;
+import org.opendaylight.controller.yang.data.api.CompositeNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,6 +50,22 @@ public class BindingBrokerImpl implements BindingAwareBroker {
 
     private Set<SALBindingModule> modules = new HashSet<SALBindingModule>();
     private Map<Class<? extends BindingAwareService>, SALBindingModule> salServiceProviders = new HashMap<Class<? extends BindingAwareService>, SALBindingModule>();
+    private MappingProvider mapping;
+    private BIFacade biFacade = new BIFacade();
+    private org.opendaylight.controller.sal.core.api.Broker.ProviderSession biSession;
+    private ExecutorService executor;
+
+    Map<Class<? extends RpcService>, RpcService> rpcImpls = Collections
+            .synchronizedMap(new HashMap<Class<? extends RpcService>, RpcService>());
+
+    private RpcProxyInvocationHandler rpcProxyHandler = new RpcProxyInvocationHandler() {
+
+        @Override
+        public Future<RpcResult<? extends DataObject>> invokeRpc(
+                RpcService proxy, QName rpc, DataObject input) {
+            return rpcProxyInvoked(proxy, rpc, input);
+        }
+    };
 
     @Override
     public ConsumerSession registerConsumer(BindingAwareConsumer consumer) {
@@ -41,9 +76,7 @@ public class BindingBrokerImpl implements BindingAwareBroker {
         consumer.onSessionInitialized(session);
 
         sessions.add(session);
-
         return session;
-
     }
 
     @Override
@@ -116,11 +149,101 @@ public class BindingBrokerImpl implements BindingAwareBroker {
 
     }
 
+    private <T extends RpcService> T newRpcProxyForSession(Class<T> service) {
+
+        RpcMapper<T> mapper = mapping.rpcMapperForClass(service);
+        if (mapper == null) {
+            log.error("Mapper for " + service + "is unavailable.");
+            return null;
+        }
+        T proxy = mapper.getConsumerProxy(rpcProxyHandler);
+
+        return proxy;
+    }
+
+    private Future<RpcResult<? extends DataObject>> rpcProxyInvoked(
+            RpcService rpcProxy, QName rpcType, DataObject inputData) {
+        if (rpcProxy == null) {
+            throw new IllegalArgumentException("Proxy must not be null");
+        }
+        if (rpcType == null) {
+            throw new IllegalArgumentException(
+                    "rpcType (QName) should not be null");
+        }
+        Future<RpcResult<? extends DataObject>> ret = null;
+
+        // Real invocation starts here
+        RpcMapper<? extends RpcService> mapper = mapping
+                .rpcMapperForProxy(rpcProxy);
+        RpcService impl = rpcImpls.get(mapper.getServiceClass());
+
+        if (impl == null) {
+            // RPC is probably remote
+            CompositeNode inputNode = null;
+            Mapper<? extends DataObject> inputMapper = mapper.getInputMapper();
+            if (inputMapper != null) {
+                inputNode = inputMapper.domFromObject(inputData);
+            }
+            Future<RpcResult<CompositeNode>> biResult = biSession.rpc(rpcType,
+                    inputNode);
+            ret = new TranslatedFuture(biResult, mapper);
+
+        } else {
+            // RPC is local
+            Callable<RpcResult<? extends DataObject>> invocation = localRpcCallableFor(
+                    impl, mapper, rpcType, inputData);
+            ret = executor.submit(invocation);
+        }
+        return ret;
+    }
+
+    private Callable<RpcResult<? extends DataObject>> localRpcCallableFor(
+            final RpcService impl,
+            final RpcMapper<? extends RpcService> mapper, final QName rpcType,
+            final DataObject inputData) {
+
+        return new Callable<RpcResult<? extends DataObject>>() {
+
+            @Override
+            public RpcResult<? extends DataObject> call() throws Exception {
+                return mapper.invokeRpcImplementation(rpcType, impl, inputData);
+            }
+        };
+    }
+
+    // Binding Independent invocation of Binding Aware RPC
+    private RpcResult<CompositeNode> invokeLocalRpc(QName rpc,
+            CompositeNode inputNode) {
+        RpcMapper<? extends RpcService> mapper = mapping.rpcMapperForData(rpc,
+                inputNode);
+
+        DataObject inputTO = mapper.getInputMapper().objectFromDom(inputNode);
+
+        RpcService impl = rpcImpls.get(mapper.getServiceClass());
+        if (impl == null) {
+            log.warn("Implementation for rpc: " + rpc + "not available.");
+        }
+        RpcResult<? extends DataObject> result = mapper
+                .invokeRpcImplementation(rpc, impl, inputTO);
+        DataObject outputTO = result.getResult();
+
+        CompositeNode outputNode = null;
+        if (outputTO != null) {
+            outputNode = mapper.getOutputMapper().domFromObject(outputTO);
+        }
+        return Rpcs.getRpcResult(result.isSuccessful(), outputNode,
+                result.getErrors());
+    }
+
     private class ConsumerSessionImpl implements
             BindingAwareBroker.ConsumerSession {
 
         private final BindingAwareConsumer consumer;
-        private Map<Class<? extends BindingAwareService>, BindingAwareService> sessionSalServices = new HashMap<Class<? extends BindingAwareService>, BindingAwareService>();
+        private Map<Class<? extends BindingAwareService>, BindingAwareService> sessionSalServices = Collections
+                .synchronizedMap(new HashMap<Class<? extends BindingAwareService>, BindingAwareService>());
+
+        private Map<Class<? extends RpcService>, RpcService> sessionRpcProxies = Collections
+                .synchronizedMap(new HashMap<Class<? extends RpcService>, RpcService>());
 
         public ConsumerSessionImpl(BindingAwareConsumer cons) {
             this.consumer = cons;
@@ -153,9 +276,27 @@ public class BindingBrokerImpl implements BindingAwareBroker {
         }
 
         @Override
-        public <T extends RpcService> T getRpcService(Class<T> module) {
-            // TODO Implement this method
-            throw new UnsupportedOperationException("Not implemented");
+        public <T extends RpcService> T getRpcService(Class<T> service) {
+            RpcService current = sessionRpcProxies.get(service);
+            if (current != null) {
+                if (service.isInstance(current)) {
+                    @SuppressWarnings("unchecked")
+                    T ret = (T) current;
+                    return ret;
+                } else {
+                    log.error("Proxy  for rpc service " + service.getName()
+                            + " does not implement the service interface");
+                    throw new IllegalStateException("Service implementation "
+                            + current.getClass().getName()
+                            + "does not implement " + service.getName());
+                }
+            } else {
+                T ret = BindingBrokerImpl.this.newRpcProxyForSession(service);
+                if (ret != null) {
+                    sessionRpcProxies.put(service, ret);
+                }
+                return ret;
+            }
         }
 
         public BindingAwareConsumer getConsumer() {
@@ -176,12 +317,20 @@ public class BindingBrokerImpl implements BindingAwareBroker {
 
         @Override
         public void addRpcImplementation(RpcService implementation) {
+            if (implementation == null) {
+                throw new IllegalArgumentException(
+                        "Implementation should not be null");
+            }
             // TODO Implement this method
             throw new UnsupportedOperationException("Not implemented");
         }
 
         @Override
         public void removeRpcImplementation(RpcService implementation) {
+            if (implementation == null) {
+                throw new IllegalArgumentException(
+                        "Implementation should not be null");
+            }
             // TODO Implement this method
             throw new UnsupportedOperationException("Not implemented");
         }
@@ -192,4 +341,96 @@ public class BindingBrokerImpl implements BindingAwareBroker {
 
     }
 
+    private class BIFacade implements Provider,RpcImplementation {
+
+        @Override
+        public Set<QName> getSupportedRpcs() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+            if (rpc == null) {
+                throw new IllegalArgumentException(
+                        "Rpc type should not be null");
+            }
+
+            return BindingBrokerImpl.this.invokeLocalRpc(rpc, input);
+        }
+
+        @Override
+        public void onSessionInitiated(
+                org.opendaylight.controller.sal.core.api.Broker.ProviderSession session) {
+            
+            BindingBrokerImpl.this.biSession = session;
+            for (SALBindingModule module : modules) {
+                try {
+                    module.onBISessionAvailable(biSession);
+                } catch(Exception e) {
+                    log.error("Module " +module +" throwed unexpected exception",e);
+                }
+            }
+        }
+
+        @Override
+        public Collection<ProviderFunctionality> getProviderFunctionality() {
+            return Collections.emptySet();
+        }
+
+    }
+
+    private static class TranslatedFuture implements
+            Future<RpcResult<? extends DataObject>> {
+        private final Future<RpcResult<CompositeNode>> realFuture;
+        private final RpcMapper<?> mapper;
+
+        public TranslatedFuture(Future<RpcResult<CompositeNode>> future,
+                RpcMapper<?> mapper) {
+            realFuture = future;
+            this.mapper = mapper;
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            return realFuture.cancel(mayInterruptIfRunning);
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return realFuture.isCancelled();
+        }
+
+        @Override
+        public boolean isDone() {
+            return realFuture.isDone();
+        }
+
+        @Override
+        public RpcResult<? extends DataObject> get()
+                throws InterruptedException, ExecutionException {
+            RpcResult<CompositeNode> val = realFuture.get();
+            return tranlate(val);
+        }
+
+        @Override
+        public RpcResult<? extends DataObject> get(long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException,
+                TimeoutException {
+            RpcResult<CompositeNode> val = realFuture.get(timeout, unit);
+            return tranlate(val);
+        }
+
+        private RpcResult<? extends DataObject> tranlate(
+                RpcResult<CompositeNode> result) {
+            CompositeNode outputNode = result.getResult();
+            DataObject outputTO = null;
+            if (outputNode != null) {
+                Mapper<?> outputMapper = mapper.getOutputMapper();
+                outputTO = outputMapper.objectFromDom(outputNode);
+            }
+            return Rpcs.getRpcResult(result.isSuccessful(), outputTO,
+                    result.getErrors());
+        }
+
+    }
 }
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java
new file mode 100644 (file)
index 0000000..cbd6b00
--- /dev/null
@@ -0,0 +1,198 @@
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.controller.sal.binding.api.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.DataCommitHandler;
+import org.opendaylight.controller.sal.binding.api.DataProviderService;
+import org.opendaylight.controller.sal.binding.api.DataValidator;
+import org.opendaylight.controller.sal.binding.spi.MappingProvider;
+import org.opendaylight.controller.sal.binding.spi.SALBindingModule;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.binding.api.DataRefresher;
+import org.opendaylight.controller.yang.binding.DataRoot;
+import org.opendaylight.controller.yang.common.RpcResult;
+import org.opendaylight.controller.yang.data.api.CompositeNode;
+
+public class DataModule implements SALBindingModule {
+
+    private BindingAwareBroker broker;
+    private org.opendaylight.controller.sal.core.api.Broker.ProviderSession biSession;
+    private MappingProvider mappingProvider;
+    private final BIFacade biFacade = new BIFacade();
+    private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
+
+    @Override
+    public void setBroker(BindingAwareBroker broker) {
+        this.broker = broker;
+    }
+
+    @Override
+    public void onBISessionAvailable(
+            org.opendaylight.controller.sal.core.api.Broker.ProviderSession session) {
+        this.biSession = session;
+        this.biDataService = session
+                .getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class);
+        // biDataService.addRefresher(store, refresher)
+
+    }
+
+    @Override
+    public void setMappingProvider(MappingProvider provider) {
+        this.mappingProvider = provider;
+
+    }
+
+    @Override
+    public Set<Class<? extends BindingAwareService>> getProvidedServices() {
+        Set<Class<? extends BindingAwareService>> ret = new HashSet<Class<? extends BindingAwareService>>();
+        ret.add(DataBrokerService.class);
+        ret.add(DataProviderService.class);
+        return ret;
+    }
+
+    @Override
+    public <T extends BindingAwareService> T getServiceForSession(
+            Class<T> service, ConsumerSession session) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    private class DataBrokerSession implements DataBrokerService {
+
+        @Override
+        public <T extends DataRoot> T getData(DataStoreIdentifier store,
+                Class<T> rootType) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public <T extends DataRoot> T getData(DataStoreIdentifier store,
+                T filter) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public <T extends DataRoot> T getCandidateData(
+                DataStoreIdentifier store, Class<T> rootType) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public <T extends DataRoot> T getCandidateData(
+                DataStoreIdentifier store, T filter) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store,
+                DataRoot changeSet) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+    }
+
+    private class DataProviderSession extends DataBrokerSession implements
+            DataProviderService {
+
+        @Override
+        public void addValidator(DataStoreIdentifier store,
+                DataValidator validator) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public void removeValidator(DataStoreIdentifier store,
+                DataValidator validator) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public void addCommitHandler(DataStoreIdentifier store,
+                DataCommitHandler provider) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public void removeCommitHandler(DataStoreIdentifier store,
+                DataCommitHandler provider) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public void addRefresher(DataStoreIdentifier store,
+                DataRefresher refresher) {
+            // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public void removeRefresher(DataStoreIdentifier store,
+                DataRefresher refresher) {
+            // TODO Auto-generated method stub
+
+        }
+
+    }
+
+    private class BIFacade
+            implements
+            org.opendaylight.controller.sal.core.api.data.DataCommitHandler,
+            org.opendaylight.controller.sal.core.api.data.DataValidator,
+            org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher {
+
+        @Override
+        public RpcResult<Void> validate(CompositeNode toValidate) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Set<DataStoreIdentifier> getSupportedDataStores() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public RpcResult<CommitTransaction> requestCommit(
+                DataStoreIdentifier store) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public void refreshData() {
+            // TODO Auto-generated method stub
+            
+        }
+
+    }
+
+}
index a7fbb240895ca7a5d7144c12d94fa25e98414cc8..b29eac2871c2a1534ead86f552a4acf5a3ddabf9 100644 (file)
@@ -8,12 +8,40 @@
 package org.opendaylight.controller.sal.binding.spi;
 
 import org.opendaylight.controller.yang.binding.DataObject;
+import org.opendaylight.controller.yang.binding.RpcService;
 import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.data.api.CompositeNode;
 
 public interface MappingProvider {
 
-    <T extends DataObject> Mapper<T> getMapper(Class<T> type);
-    Mapper<DataObject> getMapper(QName name);
+    <T extends DataObject> Mapper<T> mapperForClass(Class<T> type);
+    Mapper<DataObject> mapperForQName(QName name);
+    
+    /**
+     * Returns {@link RpcMapper} associated to class
+     * 
+     * @param type Class for which RpcMapper should provide mapping
+     * @return
+     */
+    <T extends RpcService> RpcMapper<T> rpcMapperForClass(Class<T> type);
+    
+    /**
+     * Returns {@link RpcMapper} associated to the {@link RpcService} proxy.
+     * 
+     * @param proxy
+     * @return
+     */
+    RpcMapper<? extends RpcService> rpcMapperForProxy(RpcService proxy);
+    
+    /**
+     * 
+     * 
+     * @param rpc
+     * @param inputNode
+     * @return
+     */
+    RpcMapper<? extends RpcService> rpcMapperForData(QName rpc,
+            CompositeNode inputNode);
 
     <T extends MappingExtension> MappingExtensionFactory<T> getExtensionFactory(Class<T> cls);
 
@@ -25,4 +53,6 @@ public interface MappingProvider {
         T forClass(Class<?> obj);
     }
 
+
+
 }
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java b/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java
new file mode 100644 (file)
index 0000000..0db1bc2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.sal.binding.spi;
+
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.yang.binding.DataObject;
+import org.opendaylight.controller.yang.binding.RpcService;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.common.RpcResult;
+
+public interface RpcMapper<T extends RpcService> {
+    
+    Set<QName> getRpcQNames();
+    
+    /**
+     * Returns a class object representing subinterface
+     * to whom, this mapper is assigned.
+     * 
+     * @return
+     */
+    Class<T> getServiceClass();
+    
+    /**
+     * Returns a Binding Mapper for Rpc Input Data
+     * @return
+     */
+    Mapper<?> getInputMapper();
+    /**
+     * Returns a Binding Mapper for Rpc Output Data
+     * 
+     * @return
+     */
+    Mapper<?> getOutputMapper();
+    
+    /**
+     * Returns a consumer proxy, which is responsible
+     * for invoking the rpc functionality of {@link BindingAwareBroker} implementation.
+     * 
+     * @return Proxy of {@link RpcService} assigned to this mapper.
+     */
+    T getConsumerProxy(RpcProxyInvocationHandler handler);
+    
+    /**
+     * Invokes the method of RpcService representing the supplied rpc.
+     * 
+     * @param rpc QName of Rpc
+     * @param impl Implementation of RpcService on which the method should be invoked
+     * @param baInput Input Data to RPC method
+     * @return Result of RPC invocation.
+     */
+    RpcResult<? extends DataObject> invokeRpcImplementation(QName rpc,
+            RpcService impl, DataObject baInput);
+    
+    public interface RpcProxyInvocationHandler {
+        
+        Future<RpcResult<? extends DataObject>> invokeRpc(RpcService proxy, QName rpc, DataObject input);
+    }
+}
index d81c6ac2ff9ad30a523c6814bf06effea2563330..c195fe4ae2c317807c2ed2d1ae77b867f55a26fe 100644 (file)
                        <artifactId>sal-core-api</artifactId>\r
                        <version>1.0-SNAPSHOT</version>\r
                </dependency>\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>sal-common-util</artifactId>\r
+                       <version>1.0-SNAPSHOT</version>\r
+               </dependency>\r
                <dependency>\r
                        <groupId>org.opendaylight.controller</groupId>\r
                        <artifactId>sal-core-spi</artifactId>\r
index 84bc0569504272704d3ea68605d42f6c13de0afe..b8a0b97eab9abb81b851eeda349ec6156709442a 100644 (file)
@@ -1,4 +1,3 @@
-
 /*\r
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
  *\r
@@ -8,46 +7,55 @@
  */\r
 package org.opendaylight.controller.sal.core.impl;\r
 \r
+import java.util.Collection;\r
+import java.util.Collections;\r
 import java.util.HashMap;\r
 import java.util.HashSet;\r
 import java.util.Map;\r
 import java.util.Set;\r
+import java.util.concurrent.Callable;\r
+import java.util.concurrent.ExecutorService;\r
 import java.util.concurrent.Future;\r
-\r
 import org.opendaylight.controller.sal.core.api.Broker;\r
 import org.opendaylight.controller.sal.core.api.BrokerService;\r
 import org.opendaylight.controller.sal.core.api.Consumer;\r
 import org.opendaylight.controller.sal.core.api.Provider;\r
+import org.opendaylight.controller.sal.core.api.RpcImplementation;\r
 import org.opendaylight.controller.sal.core.spi.BrokerModule;\r
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.common.RpcResult;
-import org.opendaylight.controller.yang.data.api.CompositeNode;
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.common.RpcResult;\r
+import org.opendaylight.controller.yang.data.api.CompositeNode;\r
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 \r
-\r
 public class BrokerImpl implements Broker {\r
     private static Logger log = LoggerFactory.getLogger(BrokerImpl.class);\r
 \r
-    private Set<ConsumerSessionImpl> sessions = new HashSet<ConsumerSessionImpl>();\r
-    private Set<ProviderSessionImpl> providerSessions = new HashSet<ProviderSessionImpl>();\r
-    // private ExecutorService executor;\r
-    private Set<BrokerModule> modules = new HashSet<BrokerModule>();\r
+    // Broker Generic Context\r
+    private Set<ConsumerSessionImpl> sessions = Collections\r
+            .synchronizedSet(new HashSet<ConsumerSessionImpl>());\r
+    private Set<ProviderSessionImpl> providerSessions = Collections\r
+            .synchronizedSet(new HashSet<ProviderSessionImpl>());\r
+    private Set<BrokerModule> modules = Collections\r
+            .synchronizedSet(new HashSet<BrokerModule>());\r
+    private Map<Class<? extends BrokerService>, BrokerModule> serviceProviders = Collections\r
+            .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerModule>());\r
+\r
+    // RPC Context\r
+    private Map<QName, RpcImplementation> rpcImpls = Collections\r
+            .synchronizedMap(new HashMap<QName, RpcImplementation>());\r
 \r
-    private Map<Class<? extends BrokerService>, BrokerModule> serviceProviders = new HashMap<Class<? extends BrokerService>, BrokerModule>();\r
+    // Implementation specific\r
+    private ExecutorService executor;\r
 \r
     @Override\r
     public ConsumerSession registerConsumer(Consumer consumer) {\r
         checkPredicates(consumer);\r
         log.info("Registering consumer " + consumer);\r
-\r
         ConsumerSessionImpl session = newSessionFor(consumer);\r
         consumer.onSessionInitiated(session);\r
-\r
         sessions.add(session);\r
-\r
         return session;\r
-\r
     }\r
 \r
     @Override\r
@@ -56,11 +64,26 @@ public class BrokerImpl implements Broker {
 \r
         ProviderSessionImpl session = newSessionFor(provider);\r
         provider.onSessionInitiated(session);\r
-\r
         providerSessions.add(session);\r
         return session;\r
     }\r
 \r
+    public void addModule(BrokerModule module) {\r
+        log.info("Registering broker module " + module);\r
+        if (modules.contains(module)) {\r
+            log.error("Module already registered");\r
+            throw new IllegalArgumentException("Module already exists.");\r
+        }\r
+    \r
+        Set<Class<? extends BrokerService>> provServices = module\r
+                .getProvidedServices();\r
+        for (Class<? extends BrokerService> serviceType : provServices) {\r
+            log.info("  Registering session service implementation: "\r
+                    + serviceType.getCanonicalName());\r
+            serviceProviders.put(serviceType, module);\r
+        }\r
+    }\r
+\r
     public <T extends BrokerService> T serviceFor(Class<T> service,\r
             ConsumerSessionImpl session) {\r
         BrokerModule prov = serviceProviders.get(service);\r
@@ -71,11 +94,43 @@ public class BrokerImpl implements Broker {
         return prov.getServiceForSession(service, session);\r
     }\r
 \r
-    public Future<RpcResult<CompositeNode>> invokeRpc(QName rpc,\r
+    // RPC Functionality\r
+    \r
+    private void addRpcImplementation(QName rpcType,\r
+            RpcImplementation implementation) {\r
+        synchronized (rpcImpls) {\r
+            if (rpcImpls.get(rpcType) != null) {\r
+                throw new IllegalStateException("Implementation for rpc "\r
+                        + rpcType + " is already registered.");\r
+            }\r
+            rpcImpls.put(rpcType, implementation);\r
+        }\r
+        // TODO Add notification for availability of Rpc Implementation\r
+    }\r
+\r
+    private void removeRpcImplementation(QName rpcType,\r
+            RpcImplementation implToRemove) {\r
+        synchronized (rpcImpls) {\r
+            if (implToRemove == rpcImpls.get(rpcType)) {\r
+                rpcImpls.remove(rpcType);\r
+            }\r
+        }\r
+        // TODO Add notification for removal of Rpc Implementation\r
+    }\r
+\r
+    private Future<RpcResult<CompositeNode>> invokeRpc(QName rpc,\r
             CompositeNode input) {\r
-        // TODO Implement this method\r
-        throw new UnsupportedOperationException("Not implemented");\r
+        RpcImplementation impl = rpcImpls.get(rpc);\r
+        // if()\r
+\r
+        Callable<RpcResult<CompositeNode>> call = callableFor(impl,\r
+                rpc, input);\r
+        Future<RpcResult<CompositeNode>> result = executor.submit(call);\r
+\r
+        return result;\r
     }\r
+    \r
+    // Validation\r
 \r
     private void checkPredicates(Provider prov) {\r
         if (prov == null)\r
@@ -96,34 +151,130 @@ public class BrokerImpl implements Broker {
         }\r
     }\r
 \r
+    // Private Factory methods\r
+    \r
     private ConsumerSessionImpl newSessionFor(Consumer cons) {\r
-        return new ConsumerSessionImpl(this, cons);\r
+        return new ConsumerSessionImpl(cons);\r
     }\r
 \r
     private ProviderSessionImpl newSessionFor(Provider provider) {\r
-        return new ProviderSessionImpl(this, provider);\r
+        return new ProviderSessionImpl(provider);\r
     }\r
 \r
-    public void addModule(BrokerModule module) {\r
-        log.info("Registering broker module " + module);\r
-        if (modules.contains(module)) {\r
-            log.error("Module already registered");\r
-            throw new IllegalArgumentException("Module already exists.");\r
+    private void consumerSessionClosed(ConsumerSessionImpl consumerSessionImpl) {\r
+        sessions.remove(consumerSessionImpl);\r
+        providerSessions.remove(consumerSessionImpl);\r
+    }\r
+\r
+    private static Callable<RpcResult<CompositeNode>> callableFor(\r
+            final RpcImplementation implemenation, final QName rpc,\r
+            final CompositeNode input) {\r
+\r
+        return new Callable<RpcResult<CompositeNode>>() {\r
+\r
+            @Override\r
+            public RpcResult<CompositeNode> call() throws Exception {\r
+                return implemenation.invokeRpc(rpc, input);\r
+            }\r
+        };\r
+    }\r
+    \r
+    private class ConsumerSessionImpl implements ConsumerSession {\r
+\r
+        private final Consumer consumer;\r
+\r
+        private Map<Class<? extends BrokerService>, BrokerService> instantiatedServices = Collections\r
+                .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerService>());\r
+        private boolean closed = false;\r
+\r
+        public Consumer getConsumer() {\r
+            return consumer;\r
         }\r
 \r
-        Set<Class<? extends BrokerService>> provServices = module\r
-                .getProvidedServices();\r
-        for (Class<? extends BrokerService> serviceType : provServices) {\r
-            log.info("  Registering session service implementation: "\r
-                    + serviceType.getCanonicalName());\r
-            serviceProviders.put(serviceType, module);\r
+        public ConsumerSessionImpl(Consumer consumer) {\r
+            this.consumer = consumer;\r
+        }\r
+\r
+        @Override\r
+        public Future<RpcResult<CompositeNode>> rpc(QName rpc,\r
+                CompositeNode input) {\r
+            return BrokerImpl.this.invokeRpc(rpc, input);\r
+        }\r
+\r
+        @Override\r
+        public <T extends BrokerService> T getService(Class<T> service) {\r
+            BrokerService potential = instantiatedServices.get(service);\r
+            if (potential != null) {\r
+                @SuppressWarnings("unchecked")\r
+                T ret = (T) potential;\r
+                return ret;\r
+            }\r
+            T ret = BrokerImpl.this.serviceFor(service, this);\r
+            if (ret != null) {\r
+                instantiatedServices.put(service, ret);\r
+            }\r
+            return ret;\r
+        }\r
+\r
+        @Override\r
+        public void close() {\r
+            Collection<BrokerService> toStop = instantiatedServices.values();\r
+            this.closed = true;\r
+            for (BrokerService brokerService : toStop) {\r
+                brokerService.closeSession();\r
+            }\r
+            BrokerImpl.this.consumerSessionClosed(this);\r
+        }\r
+\r
+        @Override\r
+        public boolean isClosed() {\r
+            return closed;\r
         }\r
-    }\r
 \r
-    public void consumerSessionClosed(ConsumerSessionImpl consumerSessionImpl) {\r
-        sessions.remove(consumerSessionImpl);\r
-        providerSessions.remove(consumerSessionImpl);\r
     }\r
 \r
+    private class ProviderSessionImpl extends ConsumerSessionImpl implements\r
+            ProviderSession {\r
+\r
+        private Provider provider;\r
+        private Map<QName, RpcImplementation> sessionRpcImpls = Collections.synchronizedMap(new HashMap<QName, RpcImplementation>());\r
+\r
+        public ProviderSessionImpl(Provider provider) {\r
+            super(null);\r
+            this.provider = provider;\r
+        }\r
+\r
+        @Override\r
+        public void addRpcImplementation(QName rpcType,\r
+                RpcImplementation implementation)\r
+                throws IllegalArgumentException {\r
+            if (rpcType == null) {\r
+                throw new IllegalArgumentException("rpcType must not be null");\r
+            }\r
+            if (implementation == null) {\r
+                throw new IllegalArgumentException(\r
+                        "Implementation must not be null");\r
+            }\r
+            BrokerImpl.this.addRpcImplementation(rpcType, implementation);\r
+            sessionRpcImpls.put(rpcType, implementation);\r
+        }\r
+\r
+        @Override\r
+        public void removeRpcImplementation(QName rpcType,\r
+                RpcImplementation implToRemove) throws IllegalArgumentException {\r
+            RpcImplementation localImpl = rpcImpls.get(rpcType);\r
+            if (localImpl != implToRemove) {\r
+                throw new IllegalStateException(\r
+                        "Implementation was not registered in this session");\r
+            }\r
+\r
+            BrokerImpl.this.removeRpcImplementation(rpcType, implToRemove);\r
+            sessionRpcImpls.remove(rpcType);\r
+        }\r
+\r
+        public Provider getProvider() {\r
+            return this.provider;\r
+        }\r
+\r
+    }\r
 }\r
-
diff --git a/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/ConsumerSessionImpl.java b/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/ConsumerSessionImpl.java
deleted file mode 100644 (file)
index 032dd22..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.core.impl;\r
-\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-import java.util.concurrent.Future;\r
-\r
-import org.opendaylight.controller.sal.core.api.BrokerService;\r
-import org.opendaylight.controller.sal.core.api.Consumer;\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-\r
-public class ConsumerSessionImpl implements ConsumerSession {\r
-\r
-    private final BrokerImpl broker;\r
-    private final Consumer consumer;\r
-\r
-    private Map<Class<? extends BrokerService>, BrokerService> instantiatedServices = new HashMap<Class<? extends BrokerService>, BrokerService>();\r
-    private boolean closed = false;\r
-\r
-    public Consumer getConsumer() {\r
-        return consumer;\r
-    }\r
-\r
-    public ConsumerSessionImpl(BrokerImpl broker, Consumer consumer) {\r
-        this.broker = broker;\r
-        this.consumer = consumer;\r
-    }\r
-\r
-    @Override\r
-    public Future<RpcResult<CompositeNode>> rpc(QName rpc, CompositeNode input) {\r
-        return broker.invokeRpc(rpc, input);\r
-    }\r
-\r
-    @Override\r
-    public <T extends BrokerService> T getService(Class<T> service) {\r
-        BrokerService potential = instantiatedServices.get(service);\r
-        if (potential != null) {\r
-            @SuppressWarnings("unchecked")\r
-            T ret = (T) potential;\r
-            return ret;\r
-        }\r
-        T ret = this.broker.serviceFor(service, this);\r
-        if (ret != null) {\r
-            instantiatedServices.put(service, ret);\r
-        }\r
-        return ret;\r
-    }\r
-\r
-    @Override\r
-    public void close() {\r
-        Collection<BrokerService> toStop = instantiatedServices.values();\r
-        this.closed  = true;\r
-        for (BrokerService brokerService : toStop) {\r
-            brokerService.closeSession();\r
-        }\r
-        broker.consumerSessionClosed(this);\r
-    }\r
-\r
-    @Override\r
-    public boolean isClosed() {\r
-        return closed;\r
-    }\r
-\r
-}
@@ -5,7 +5,7 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
  */\r
-package org.opendaylight.controller.sal.core.impl.data;\r
+package org.opendaylight.controller.sal.core.impl;\r
 \r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
@@ -13,9 +13,11 @@ import java.util.HashSet;
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
+import java.util.concurrent.ExecutorService;\r
 import java.util.concurrent.Future;\r
 \r
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
+import org.opendaylight.controller.sal.common.util.Rpcs;\r
 import org.opendaylight.controller.sal.core.api.BrokerService;\r
 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
@@ -27,7 +29,6 @@ import org.opendaylight.controller.sal.core.api.data.DataProviderService;
 import org.opendaylight.controller.sal.core.api.data.DataValidator;\r
 import org.opendaylight.controller.sal.core.api.data.DataCommitHandler.CommitTransaction;\r
 import org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher;\r
-import org.opendaylight.controller.sal.core.impl.RpcUtils;\r
 import org.opendaylight.controller.sal.core.spi.BrokerModule;\r
 import org.opendaylight.controller.yang.common.RpcError;\r
 import org.opendaylight.controller.yang.common.RpcResult;\r
@@ -36,33 +37,40 @@ import org.opendaylight.controller.yang.data.api.CompositeNodeModification;
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 \r
+import com.google.common.collect.ImmutableSet;\r
 \r
 public class DataBrokerModule implements BrokerModule {\r
 \r
     private static final Logger log = LoggerFactory\r
             .getLogger(DataBrokerModule.class);\r
 \r
+    private static final Set<Class<? extends ProviderFunctionality>> SUPPORTED_PROVIDER_FUNCTIONALITY = ImmutableSet\r
+            .of((Class<? extends ProviderFunctionality>) DataValidator.class,\r
+                    DataRefresher.class, DataCommitHandler.class);\r
+\r
+    private static final Set<Class<? extends BrokerService>> PROVIDED_SESSION_SERVICES = ImmutableSet\r
+            .of((Class<? extends BrokerService>) DataBrokerService.class,\r
+                    DataProviderService.class);\r
+\r
     private Map<DataStoreIdentifier, StoreContext> storeContext;\r
 \r
+    private ExecutorService executor;\r
+    \r
     private SequentialCommitHandlerCoordinator coordinator = new SequentialCommitHandlerCoordinator();\r
 \r
     @Override\r
     public Set<Class<? extends BrokerService>> getProvidedServices() {\r
-        // FIXME: Refactor\r
-        Set<Class<? extends BrokerService>> ret = new HashSet<Class<? extends BrokerService>>();\r
-        ret.add(DataBrokerService.class);\r
-        ret.add(DataProviderService.class);\r
-        return ret;\r
+        return PROVIDED_SESSION_SERVICES;\r
     }\r
 \r
     @Override\r
     public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {\r
-        // FIXME Refactor\r
-        Set<Class<? extends ProviderFunctionality>> ret = new HashSet<Class<? extends ProviderFunctionality>>();\r
-        ret.add(DataValidator.class);\r
-        ret.add(DataCommitHandler.class);\r
-        ret.add(DataRefresher.class);\r
-        return ret;\r
+        return SUPPORTED_PROVIDER_FUNCTIONALITY;\r
+    }\r
+\r
+    @Override\r
+    public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {\r
+        return Collections.emptySet();\r
     }\r
 \r
     @Override\r
@@ -85,25 +93,24 @@ public class DataBrokerModule implements BrokerModule {
     }\r
 \r
     private DataProviderService newDataProviderService(ConsumerSession session) {\r
-        // TODO Implement this method\r
-        throw new UnsupportedOperationException("Not implemented");\r
+        return new DataProviderSession();\r
     }\r
 \r
     private DataBrokerService newDataConsumerService(ConsumerSession session) {\r
-        // TODO Implement this method\r
-        throw new UnsupportedOperationException("Not implemented");\r
+        return new DataConsumerSession();\r
     }\r
 \r
-    @Override\r
-    public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {\r
-        // TODO Implement this method\r
-        throw new UnsupportedOperationException("Not implemented");\r
+    private StoreContext context(DataStoreIdentifier store) {\r
+        return storeContext.get(store);\r
     }\r
 \r
     private static class StoreContext {\r
-        private Set<DataCommitHandler> commitHandlers = new HashSet<DataCommitHandler>();\r
-        private Set<DataValidator> validators = new HashSet<DataValidator>();\r
-        private Set<DataRefresher> refreshers = new HashSet<DataRefresher>();\r
+        private Set<DataCommitHandler> commitHandlers = Collections\r
+                .synchronizedSet(new HashSet<DataCommitHandler>());\r
+        private Set<DataValidator> validators = Collections\r
+                .synchronizedSet(new HashSet<DataValidator>());\r
+        private Set<DataRefresher> refreshers = Collections\r
+                .synchronizedSet(new HashSet<DataRefresher>());\r
     }\r
 \r
     private class DataConsumerSession implements DataBrokerService {\r
@@ -153,10 +160,12 @@ public class DataBrokerModule implements BrokerModule {
             throw new UnsupportedOperationException("Not implemented");\r
         }\r
 \r
-    }\r
+        @Override\r
+        public Set<DataStoreIdentifier> getDataStores() {\r
+            // TODO Auto-generated method stub\r
+            return null;\r
+        }\r
 \r
-    private StoreContext context(DataStoreIdentifier store) {\r
-        return storeContext.get(store);\r
     }\r
 \r
     private class DataProviderSession extends DataConsumerSession implements\r
@@ -265,7 +274,7 @@ public class DataBrokerModule implements BrokerModule {
             }\r
             CommitTransaction transaction = new SequentialCommitTransaction(\r
                     store, transactions);\r
-            return RpcUtils.getRpcResult(successful, transaction, errors);\r
+            return Rpcs.getRpcResult(successful, transaction, errors);\r
         }\r
 \r
         @Override\r
@@ -306,7 +315,7 @@ public class DataBrokerModule implements BrokerModule {
                     break;\r
             }\r
 \r
-            return RpcUtils.getRpcResult(successful, null, errors);\r
+            return Rpcs.getRpcResult(successful, null, errors);\r
         }\r
 \r
         @Override\r
@@ -330,7 +339,7 @@ public class DataBrokerModule implements BrokerModule {
                     break;\r
             }\r
 \r
-            return RpcUtils.getRpcResult(successful, null, errors);\r
+            return Rpcs.getRpcResult(successful, null, errors);\r
         }\r
 \r
         @Override\r
@@ -374,7 +383,7 @@ public class DataBrokerModule implements BrokerModule {
                     break;\r
             }\r
 \r
-            return RpcUtils.getRpcResult(successful, null, errors);\r
+            return Rpcs.getRpcResult(successful, null, errors);\r
         }\r
 \r
         @Override\r
@@ -408,4 +417,3 @@ public class DataBrokerModule implements BrokerModule {
         }\r
     }\r
 }\r
-
@@ -22,7 +22,6 @@ import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;\r
 import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;\r
 import org.opendaylight.controller.sal.core.api.notify.NotificationService;\r
-import org.opendaylight.controller.sal.core.impl.BrokerServiceImpl;\r
 import org.opendaylight.controller.sal.core.spi.BrokerModule;\r
 import org.opendaylight.controller.yang.common.QName;\r
 import org.opendaylight.controller.yang.data.api.CompositeNode;\r
@@ -40,21 +39,25 @@ public class NotificationModule implements BrokerModule {
     private Multimap<QName, NotificationListener> listeners = HashMultimap\r
             .create();\r
 \r
-    private static final Set<Class<? extends BrokerService>> providedServices = ImmutableSet\r
+    private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet\r
             .of((Class<? extends BrokerService>) NotificationService.class,\r
                     NotificationProviderService.class);\r
 \r
+    private static final Set<Class<? extends ConsumerFunctionality>> SUPPORTED_CONSUMER_FUNCTIONALITY = ImmutableSet\r
+            .of((Class<? extends ConsumerFunctionality>) NotificationListener.class,\r
+                    NotificationListener.class); // Workaround: if we use the\r
+                                                 // version of method with only\r
+                                                 // one argument, the generics\r
+                                                 // inference will not work\r
+\r
     @Override\r
     public Set<Class<? extends BrokerService>> getProvidedServices() {\r
-        return providedServices;\r
+        return PROVIDED_SERVICE_TYPE;\r
     }\r
 \r
     @Override\r
     public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {\r
-        // FIXME Refactor\r
-        Set<Class<? extends ConsumerFunctionality>> ret = new HashSet<Class<? extends ConsumerFunctionality>>();\r
-        ret.add(NotificationListener.class);\r
-        return ret;\r
+        return SUPPORTED_CONSUMER_FUNCTIONALITY;\r
     }\r
 \r
     @Override\r
@@ -107,8 +110,8 @@ public class NotificationModule implements BrokerModule {
         return new NotificationProviderSessionImpl();\r
     }\r
 \r
-    private class NotificationConsumerSessionImpl extends BrokerServiceImpl\r
-            implements NotificationService {\r
+    private class NotificationConsumerSessionImpl implements\r
+            NotificationService {\r
 \r
         private Multimap<QName, NotificationListener> consumerListeners = HashMultimap\r
                 .create();\r
diff --git a/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/ProviderSessionImpl.java b/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/ProviderSessionImpl.java
deleted file mode 100644 (file)
index e87b8bb..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.core.impl;\r
-\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.core.api.Provider;\r
-import org.opendaylight.controller.sal.core.api.RpcImplementation;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.controller.yang.common.QName;
-\r
-\r
-public class ProviderSessionImpl extends ConsumerSessionImpl implements\r
-        ProviderSession {\r
-\r
-    private Provider provider;\r
-\r
-    public ProviderSessionImpl(BrokerImpl broker, Provider provider) {\r
-        super(broker, null);\r
-        this.provider = provider;\r
-    }\r
-\r
-    @Override\r
-    public void addRpcImplementation(QName rpcType,\r
-            RpcImplementation implementation) throws IllegalArgumentException {\r
-        // TODO Implement this method\r
-        throw new UnsupportedOperationException("Not implemented");\r
-    }\r
-\r
-    @Override\r
-    public void removeRpcImplementation(QName rpcType,\r
-            RpcImplementation implementation) throws IllegalArgumentException {\r
-        // TODO Implement this method\r
-        throw new UnsupportedOperationException("Not implemented");\r
-    }\r
-\r
-    public Provider getProvider() {\r
-        return this.provider;\r
-    }\r
-\r
-}\r
-
diff --git a/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/notify/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/notify/package-info.java
deleted file mode 100644 (file)
index c068196..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-
-package org.opendaylight.controller.sal.core.impl.notify;
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/rpc/RpcModule.java b/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/rpc/RpcModule.java
deleted file mode 100644 (file)
index 58ceb5f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.opendaylight.controller.sal.core.impl.rpc;\r
-\r
-public interface RpcModule {\r
-\r
-}\r
diff --git a/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/rpc/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-broker-impl/src/main/java/org/opendaylight/controller/sal/core/impl/rpc/package-info.java
deleted file mode 100644 (file)
index 41e9bcb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*\r
-  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
-  *\r
-  * This program and the accompanying materials are made available under the\r
-  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
-  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
-  */\r
-package org.opendaylight.controller.sal.core.impl.rpc;
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-common-util/pom.xml b/opendaylight/sal/yang-prototype/sal/sal-common-util/pom.xml
new file mode 100644 (file)
index 0000000..b8be514
--- /dev/null
@@ -0,0 +1,24 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+       <modelVersion>4.0.0</modelVersion>\r
+       <parent>\r
+               <groupId>org.opendaylight.controller</groupId>\r
+               <artifactId>sal</artifactId>\r
+               <version>1.0-SNAPSHOT</version>\r
+       </parent>\r
+       <artifactId>sal-common-util</artifactId>\r
+\r
+       <dependencies>\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>yang-common</artifactId>\r
+                       <version>1.0</version>\r
+               </dependency>\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>sal-common</artifactId>\r
+                       <version>1.0-SNAPSHOT</version>\r
+               </dependency>\r
+       </dependencies>
+
+</project>
\ No newline at end of file
@@ -5,38 +5,17 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
  */\r
-package org.opendaylight.controller.sal.core.impl;\r
+package org.opendaylight.controller.sal.common.util;\r
 \r
 import java.util.ArrayList;\r
 import java.util.Collection;\r
 import java.util.Collections;\r
-import java.util.List;\r
-import java.util.concurrent.Callable;\r
-\r
-import org.opendaylight.controller.sal.core.api.RpcImplementation;\r
-import org.opendaylight.controller.yang.common.QName;\r
 import org.opendaylight.controller.yang.common.RpcError;\r
 import org.opendaylight.controller.yang.common.RpcResult;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-\r
-\r
-public class RpcUtils {\r
-\r
-    Callable<RpcResult<CompositeNode>> callableFor(\r
-            final RpcImplementation implemenation, final QName rpc,\r
-            final CompositeNode input) {\r
-\r
-        return new Callable<RpcResult<CompositeNode>>() {\r
-\r
-            @Override\r
-            public RpcResult<CompositeNode> call() throws Exception {\r
-                return implemenation.invokeRpc(rpc, input);\r
-            }\r
-        };\r
-    }\r
 \r
+public class Rpcs {\r
     public static <T> RpcResult<T> getRpcResult(boolean successful, T result,\r
-            List<RpcError> errors) {\r
+            Collection<RpcError> errors) {\r
         RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);\r
         return ret;\r
     }\r
@@ -47,7 +26,8 @@ public class RpcUtils {
         private final T result;\r
         private final boolean successful;\r
 \r
-        public RpcResultTO(boolean successful, T result, List<RpcError> errors) {\r
+        public RpcResultTO(boolean successful, T result,\r
+                Collection<RpcError> errors) {\r
             this.successful = successful;\r
             this.result = result;\r
             this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(\r
@@ -71,4 +51,3 @@ public class RpcUtils {
 \r
     }\r
 }\r
-
index abdd3ad656f831bf60893cb7e5e8ce4cf878d738..7ced1746fc5fd86c639b01541742d0d2b3636317 100644 (file)
@@ -1,27 +1,29 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-  <modelVersion>4.0.0</modelVersion>\r
-  <parent>\r
-    <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>sal</artifactId>\r
-    <version>1.0-SNAPSHOT</version>\r
-  </parent>\r
-   <artifactId>sal-core-api</artifactId>\r
-   \r
-   <dependencies>\r
-               <dependency>\r
-               <groupId>org.opendaylight.controller</groupId>\r
-               <artifactId>sal-common</artifactId>\r
-               <version>1.0-SNAPSHOT</version>\r
-       </dependency>\r
-       <dependency>\r
-               <groupId>org.opendaylight.controller</groupId>\r
-               <artifactId>yang-data-api</artifactId>\r
-               <version>1.0</version>\r
-       </dependency>\r
-       <dependency>\r
-               <groupId>org.opendaylight.controller</groupId>\r
-               <artifactId>yang-model-api</artifactId>\r
-               <version>1.0</version>\r
-       </dependency>\r
-   </dependencies>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+       <modelVersion>4.0.0</modelVersion>\r
+       <parent>\r
+               <groupId>org.opendaylight.controller</groupId>\r
+               <artifactId>sal</artifactId>\r
+               <version>1.0-SNAPSHOT</version>\r
+       </parent>\r
+       <artifactId>sal-core-api</artifactId>\r
+\r
+       <dependencies>\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>sal-common</artifactId>\r
+                       <version>1.0-SNAPSHOT</version>\r
+               </dependency>\r
+\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>yang-data-api</artifactId>\r
+                       <version>1.0</version>\r
+               </dependency>\r
+               <dependency>\r
+                       <groupId>org.opendaylight.controller</groupId>\r
+                       <artifactId>yang-model-api</artifactId>\r
+                       <version>1.0</version>\r
+               </dependency>\r
+       </dependencies>
 </project>
\ No newline at end of file
index f5f393852e8f7050dad9de610a522eae6854a675..d74a7d146ddf7dd63d502aab9d720624566105d9 100644 (file)
@@ -7,6 +7,7 @@
  */\r
 package org.opendaylight.controller.sal.core.api.data;\r
 \r
+import java.util.Set;\r
 import java.util.concurrent.Future;\r
 \r
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
@@ -29,6 +30,9 @@ import org.opendaylight.controller.yang.data.api.Node;
  */\r
 public interface DataBrokerService extends BrokerService {\r
 \r
+    \r
+    Set<DataStoreIdentifier> getDataStores();\r
+    \r
     /**\r
      * Returns a data from specified Data Store.\r
      * \r
diff --git a/opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java b/opendaylight/sal/yang-prototype/sal/sal-core-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java
new file mode 100644 (file)
index 0000000..22abdc2
--- /dev/null
@@ -0,0 +1,42 @@
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.sal.core.api.model;\r
+\r
+import org.opendaylight.controller.sal.core.api.BrokerService;\r
+import org.opendaylight.controller.yang.model.api.Module;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+\r
+public interface SchemaService extends BrokerService {\r
+\r
+    /**\r
+     * Registers a YANG module to session and global context \r
+     * \r
+     * @param module\r
+     */\r
+    void addModule(Module module);\r
+    \r
+    /**\r
+     * Unregisters a YANG module from session context\r
+     * \r
+     * @param module\r
+     */\r
+    void removeModule(Module module);\r
+    \r
+    /**\r
+     * Returns session specific YANG schema context\r
+     * @return\r
+     */\r
+    SchemaContext getSessionContext();\r
+    \r
+    /**\r
+     * Returns global schema context\r
+     * \r
+     * @return\r
+     */\r
+    SchemaContext getGlobalContext();\r
+}\r
index b582349f544fc28cfd70fe2bfbcd0944c1d21bf6..fa0ea393ab4bcea4a3dba91395c6eac7e2d9660b 100644 (file)
@@ -12,7 +12,7 @@ import java.io.IOException;
 import java.io.InputStreamReader;\r
 \r
 import org.opendaylight.controller.sal.core.impl.BrokerImpl;\r
-import org.opendaylight.controller.sal.core.impl.notify.NotificationModule;\r
+import org.opendaylight.controller.sal.core.impl.NotificationModule;\r
 \r
 \r
 public class SALDemo {\r
index fc06a8c9882ec2e20aec2c75563a10ceda3422e4..27aabca6fd7c9ffc35c2127ab0a6bd0ea4be156b 100644 (file)
@@ -108,10 +108,14 @@ one.topology.init = function(json) {
                        enable: true,
                        type: 'Native',
                        onMouseEnter: function(node, eventInfo, e) {
-                               if (node.id != undefined) // if node
+                               // if node
+                               if (node.id != undefined) {
                                        one.topology.graph.canvas.getElement().style.cursor = 'move';
-                               else if (eventInfo.edge != undefined && eventInfo.edge.nodeTo.data["$type"] == "swtch" && eventInfo.edge.nodeFrom.data["$type"] == "swtch")
+                               } else if (eventInfo.edge != undefined && 
+                                               eventInfo.edge.nodeTo.data["$type"] == "swtch" && 
+                                               eventInfo.edge.nodeFrom.data["$type"] == "swtch") {
                                        one.topology.graph.canvas.getElement().style.cursor = 'pointer';
+                               }
                        },
                        onMouseLeave: function(node, eventInfo, e) {
                                one.topology.graph.canvas.getElement().style.cursor = '';
@@ -137,7 +141,11 @@ one.topology.init = function(json) {
                                $.post('/controller/web/topology/node/' + did, data);
                        },
                        onClick: function(node, eventInfo, e) {
-                               return false;
+                               if(one.f.topology === undefined) {
+                                       return false;
+                               } else {
+                                       one.f.topology.Events.onClick(node, eventInfo);
+                               }
                        }
                },
                iterations: 200,
@@ -177,6 +185,7 @@ one.topology.init = function(json) {
                        style.textAlign = "center";
                }
        });
+
        one.topology.graph.loadJSON(json);
        // compute positions incrementally and animate.
        one.topology.graph.computeIncremental({
@@ -194,7 +203,7 @@ one.topology.init = function(json) {
                                        node.setPos(new $jit.Complex(x, y), "end");
                                }
                        }
-                       console.log('done');
+                        console.log('done');
                        one.topology.graph.animate({
                                modes: ['linear'],
                                transition: $jit.Trans.Elastic.easeOut,
@@ -215,4 +224,4 @@ one.topology.update = function() {
 /** INIT */
 $.getJSON(one.global.remoteAddress+"controller/web/topology/visual.json", function(data) {
        one.topology.init(data);
-});
\ No newline at end of file
+});