Added Router code generation and unit tests for runtime code generator 27/1227/3
authorTony Tkacik <ttkacik@cisco.com>
Tue, 17 Sep 2013 15:32:11 +0000 (17:32 +0200)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 18 Sep 2013 07:29:04 +0000 (07:29 +0000)
Added implementation of Router generation
  - SAL implementation of service responsible for routing requests
    to southbound components based on ContextReference field,
    which is conceptually same as NodeType in HARD SAL, but more
    flexible and does allow selecting implementation on different
    fields than only NodeType.

Moved runtime code generation code to separate packages .codegen

Change-Id: I3c89151071c6e34af1490a79b4f19f6195a878a5
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
31 files changed:
opendaylight/sal/yang-prototype/sal/pom.xml
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/codegen/RuntimeCodeHelper.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeSpecification.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/_DataBrokerImpl.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/Constants.xtend [moved from opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/Constants.xtend with 84% similarity]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/PropertiesUtils.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/package-info.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java [deleted file]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/test/org/opendaylight/controller/sal/binding/test/GenerationTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarUpdate.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooUpdate.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/Grouping.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/InheritedContextInput.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObject.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/SimpleInput.java [new file with mode: 0644]

index 0442e8f9b2646d8f9b4d159fdfff7ea1e47d0287..75f9d68bdd816c88a1d85802c386592c24cf9054 100644 (file)
@@ -25,7 +25,7 @@
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <slf4j.version>1.7.2</slf4j.version>
                <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
-               <yang.version>0.5.7-SNAPSHOT</yang.version>
+               <yang.version>0.5.8-SNAPSHOT</yang.version>
                <maven.bundle.version>2.4.0</maven.bundle.version>
         <releaseplugin.version>2.3.2</releaseplugin.version>
         <guava.version>14.0.1</guava.version>
index 549e427d82e816fb4374d3b80b3b44e2b9aeee1d..96a16dcd5772d6000421f680259b3373d4f978c3 100644 (file)
 <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>
-               <groupId>org.opendaylight.controller</groupId>
-               <artifactId>sal-parent</artifactId>
-               <version>1.0-SNAPSHOT</version>
-       </parent>
-       <artifactId>sal-binding-broker-impl</artifactId>
-       <packaging>bundle</packaging>
+    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>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-binding-broker-impl</artifactId>
+    <packaging>bundle</packaging>
     <scm>
-      <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-      <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-      <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
     </scm>
 
-       <build>
-               <plugins>
-                       <plugin>
-                               <groupId>org.apache.felix</groupId>
-                               <artifactId>maven-bundle-plugin</artifactId>
-                               <version>${maven.bundle.version}</version>
-                               <extensions>true</extensions>
-                               <configuration>
-                                       <instructions>
-                                               <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
-                                               <Bundle-Activator>org.opendaylight.controller.sal.binding.impl.BrokerActivator</Bundle-Activator>
-                                               <Private-Package>
-                                                       org.opendaylight.controller.sal.binding.impl,
-                                                       org.opendaylight.controller.sal.binding.impl.utils,
-                                                       org.eclipse.xtend2.lib,
-                                                       org.eclipse.xtext.xbase.*
-                                               </Private-Package>
-                                       </instructions>
-                               </configuration>
-                       </plugin>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven.bundle.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Bundle-Activator>org.opendaylight.controller.sal.binding.impl.BrokerActivator</Bundle-Activator>
+                        <Private-Package>
+                            org.opendaylight.controller.sal.binding.impl,
+                            org.opendaylight.controller.sal.binding.impl.*,
+                            org.opendaylight.controller.sal.binding.codegen.*,
+                            org.eclipse.xtend2.lib,
+                            org.eclipse.xtend.lib,
+                            org.eclipse.xtext.xbase.*
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
 
-                       <plugin>
-                               <groupId>org.eclipse.xtend</groupId>
-                               <artifactId>xtend-maven-plugin</artifactId>
-                               <version>2.4.2</version>
-                               <executions>
-                                       <execution>
-                                               <goals>
-                                                       <goal>compile</goal>
-                                               </goals>
-                                               <configuration>
-                                                       <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
-                                               </configuration>
-                                       </execution>
-                               </executions>
-                       </plugin>
-                       <plugin>
-                               <artifactId>maven-clean-plugin</artifactId>
-                               <version>2.4.1</version>
-                               <configuration>
-                                       <filesets>
-                                               <fileset>
-                                                       <directory>${basedir}/src/main/xtend-gen</directory>
-                                                       <includes>
-                                                               <include>**</include>
-                                                       </includes>
-                                               </fileset>
-                                       </filesets>
-                               </configuration>
-                       </plugin>
-               </plugins>
-       </build>
+            <plugin>
+                <groupId>org.eclipse.xtend</groupId>
+                <artifactId>xtend-maven-plugin</artifactId>
+                <version>2.4.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+                <version>2.4.1</version>
+                <configuration>
+                    <filesets>
+                        <fileset>
+                            <directory>${basedir}/src/main/xtend-gen</directory>
+                            <includes>
+                                <include>**</include>
+                            </includes>
+                        </fileset>
+                    </filesets>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
-       <dependencies>
-               <dependency>
-                       <groupId>org.opendaylight.controller</groupId>
-                       <artifactId>sal-common-util</artifactId>
-                       <version>1.0-SNAPSHOT</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.opendaylight.controller</groupId>
-                       <artifactId>sal-binding-api</artifactId>
-                       <version>1.0-SNAPSHOT</version>
-               </dependency>
-               <!-- >dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-core-api</artifactId> 
-                       <version>1.0-SNAPSHOT</version> </dependency -->
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <!-- >dependency> <groupId>org.opendaylight.controller</groupId> 
+            <artifactId>sal-core-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency -->
 
-               <dependency>
-                       <groupId>org.slf4j</groupId>
-                       <artifactId>slf4j-api</artifactId>
-               </dependency>
-               <dependency>
-                       <groupId>org.osgi</groupId>
-                       <artifactId>org.osgi.core</artifactId>
-                       <version>5.0.0</version>
-               </dependency>
-               <dependency>
-                       <groupId>com.google.guava</groupId>
-                       <artifactId>guava</artifactId>
-               </dependency>
-               <dependency>
-                       <groupId>org.reflections</groupId>
-                       <artifactId>reflections</artifactId>
-                       <version>0.9.9-RC1</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.javassist</groupId>
-                       <artifactId>javassist</artifactId>
-                       <version>3.17.1-GA</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.eclipse.xtend</groupId>
-                       <artifactId>org.eclipse.xtend.lib</artifactId>
-                       <version>2.4.2</version>
-               </dependency>
-       </dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.reflections</groupId>
+            <artifactId>reflections</artifactId>
+            <version>0.9.9-RC1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.17.1-GA</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.xtend</groupId>
+            <artifactId>org.eclipse.xtend.lib</artifactId>
+            <version>2.4.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend
new file mode 100644 (file)
index 0000000..6bdb3c8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.codegen
+
+import java.util.Map
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+
+class RuntimeCodeHelper {
+    /**
+     * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
+     * 
+     * Note: This method uses reflection, but access to delegate field should be 
+     * avoided and called only if neccessary.
+     * 
+     */
+    public static def <T extends RpcService> getDelegate(RpcService proxy) {
+        val field = proxy.class.getField(DELEGATE_FIELD)
+        if (field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
+        return field.get(proxy) as T
+    }
+
+    /**
+     * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
+     * 
+     * Note: This method uses reflection, but setting delegate field should not occur too much
+     * to introduce any significant performance hits.
+     * 
+     */
+    public static def void setDelegate(RpcService proxy, RpcService delegate) {
+        val field = proxy.class.getField(DELEGATE_FIELD)
+        if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
+        if (field.type.isAssignableFrom(delegate.class)) {
+            field.set(proxy, delegate)
+        } else
+            throw new IllegalArgumentException("delegate class is not assignable to proxy");
+    }
+
+    public static def Map<InstanceIdentifier, ? extends RpcService> getRoutingTable(RpcService target,
+        Class<? extends BaseIdentity> tableClass) {
+        val field = target.class.getField(tableClass.routingTableField)
+        if (field == null) throw new UnsupportedOperationException(
+            "Unable to get routing table. Table field does not exists");
+        return field.get(target) as Map<InstanceIdentifier, ? extends RpcService>;
+    }
+
+    public static def void setRoutingTable(RpcService target, Class<? extends BaseIdentity> tableClass,
+        Map<InstanceIdentifier, ? extends RpcService> routingTable) {
+         val field = target.class.getField(tableClass.routingTableField)
+        if (field == null) throw new UnsupportedOperationException(
+            "Unable to set routing table. Table field does not exists");
+        field.set(target,routingTable);
+        
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeSpecification.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeSpecification.xtend
new file mode 100644 (file)
index 0000000..c6e76c2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.codegen
+
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import org.opendaylight.yangtools.yang.binding.NotificationListener
+
+/**
+ * 
+ * 
+ */
+class RuntimeCodeSpecification {
+
+    public static val PACKAGE_PREFIX = "_gen.";
+
+    public static val DIRECT_PROXY_SUFFIX = "DirectProxy";
+    public static val ROUTER_SUFFIX = "Router";
+    public static val INVOKER_SUFFIX = "Invoker";
+
+    public static val DELEGATE_FIELD = "_delegate"
+    public static val ROUTING_TABLE_FIELD_PREFIX = "_routes_"
+
+    public static def getInvokerName(Class<? extends NotificationListener> listener) {
+        getGeneratedName(listener, INVOKER_SUFFIX);
+    }
+
+    /**
+     * Returns a name for DirectProxy implementation
+     * 
+     * 
+     */
+    public static def getDirectProxyName(Class<? extends RpcService> base) {
+        getGeneratedName(base, DIRECT_PROXY_SUFFIX);
+    }
+
+    /**
+     * Returns a name for Router implementation
+     * 
+     */
+    public static def getRouterName(Class<? extends RpcService> base) {
+        getGeneratedName(base, ROUTER_SUFFIX);
+    }
+
+    /**
+     * Returns a name for generated interface
+     * 
+     */
+    public static def getGeneratedName(Class<?> cls, String suffix) {
+        '''«PACKAGE_PREFIX»«cls.package.name».«cls.simpleName»$«suffix»'''.toString()
+    }
+
+    /**
+     * Returns a field name for specified routing context
+     * 
+     */
+    public static def getRoutingTableField(Class<? extends BaseIdentity> routingContext) {
+        return '''_routes_«routingContext.simpleName»'''.toString;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.xtend
new file mode 100644 (file)
index 0000000..18d3e26
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.codegen
+
+import java.lang.reflect.Method
+import org.opendaylight.yangtools.yang.binding.Notification
+
+public static class YangtoolsMappingHelper {
+
+    public static def boolean isNotificationCallback(Method it) {
+        return name.startsWith("on") && parameterTypes.size === 1 &&
+            Notification.isAssignableFrom(parameterTypes.get(0))
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/JavassistUtils.java
new file mode 100644 (file)
index 0000000..c6be284
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.codegen.impl;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+
+public class JavassistUtils {
+
+    public static interface ClassGenerator {
+        void process(CtClass cls);
+    }
+
+    public static interface MethodGenerator {
+        void process(CtMethod method);
+    }
+
+    public static interface FieldGenerator {
+        void process(CtField field);
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend
new file mode 100644 (file)
index 0000000..4324b4e
--- /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.sal.binding.codegen.impl
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import javassist.CtMethod
+import java.lang.reflect.Method
+
+@Data
+class RoutingPair {
+
+    @Property
+    val Class<? extends BaseIdentity> context;
+    @Property
+    val CtMethod getter;
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend
new file mode 100644 (file)
index 0000000..3b3f419
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.codegen.impl
+
+import javassist.ClassPool
+import org.opendaylight.yangtools.yang.binding.RpcService
+
+import javassist.CtClass
+import static com.google.common.base.Preconditions.*
+
+import javassist.CtField
+import javassist.Modifier
+import javassist.CtMethod
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+
+import java.util.Map
+import java.util.HashMap
+import javassist.NotFoundException
+import javassist.LoaderClassPath
+import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.MethodGenerator
+import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.ClassGenerator
+import org.opendaylight.yangtools.yang.binding.NotificationListener
+import org.opendaylight.yangtools.yang.binding.Notification
+import java.util.Arrays
+
+import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+
+class RuntimeCodeGenerator {
+
+    val ClassPool classPool;
+
+    public new(ClassPool pool) {
+        classPool = pool;
+    }
+
+    def <T extends RpcService> Class<? extends T> generateDirectProxy(Class<T> iface) {
+        val supertype = iface.asCtClass
+        val targetCls = createClass(iface.directProxyName, supertype) [
+            field(DELEGATE_FIELD, iface);
+            implementMethodsFrom(supertype) [
+                body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
+            ]
+        ]
+        return targetCls.toClass(iface.classLoader)
+    }
+
+    def <T extends RpcService> Class<? extends T> generateRouter(Class<T> iface) {
+        val supertype = iface.asCtClass
+        val targetCls = createClass(iface.routerName, supertype) [
+            //field(ROUTING_TABLE_FIELD,Map)
+            field(DELEGATE_FIELD, iface)
+            val contexts = new HashMap<String, Class<? extends BaseIdentity>>();
+            // We search for routing pairs and add fields
+            supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
+                val routingPair = method.routingContextInput;
+                if (routingPair !== null)
+                    contexts.put(routingPair.context.routingTableField, routingPair.context);
+            ]
+            for (ctx : contexts.entrySet) {
+                field(ctx.key, Map)
+            }
+            implementMethodsFrom(supertype) [
+                if (parameterTypes.size === 1) {
+                    val routingPair = routingContextInput;
+                    val bodyTmp = '''
+                    {
+                        final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»();
+                        «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier);
+                        if(instance == null) {
+                           instance = «DELEGATE_FIELD»;
+                        }
+                        return ($r) instance.«it.name»($$);
+                    }'''
+                    body = bodyTmp
+                } else if (parameterTypes.size === 0) {
+                    body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
+                }
+            ]
+        ]
+        return targetCls.toClass(iface.classLoader)
+    }
+
+    def Class<?> generateListenerInvoker(Class<? extends NotificationListener> iface) {
+        val targetCls = createClass(iface.invokerName) [
+            field(DELEGATE_FIELD, iface)
+            it.method(Void, "invoke", Notification) [
+                val callbacks = iface.methods.filter[notificationCallback]
+                body = '''
+                    {
+                        «FOR callback : callbacks SEPARATOR " else "»
+                            if($1 instanceof «val cls = callback.parameterTypes.get(0).name») {
+                                «DELEGATE_FIELD».«callback.name»((«cls») $1);
+                                return;
+                            }
+                        «ENDFOR»
+                    }
+                '''
+            ]
+        ]
+        return targetCls.toClass(iface.classLoader);
+    }
+
+    def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
+        val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
+        function1.process(method);
+        it.addMethod(method);
+    }
+
+    private def routingContextInput(CtMethod method) {
+        val inputClass = method.parameterTypes.get(0);
+        return inputClass.contextInstance;
+    }
+
+    private def RoutingPair getContextInstance(CtClass dataClass) {
+        for (method : dataClass.methods) {
+            if (method.parameterTypes.size === 0 && method.name.startsWith("get")) {
+                for (annotation : method.availableAnnotations) {
+                    if (annotation instanceof RoutingContext) {
+                        return new RoutingPair((annotation as RoutingContext).value, method)
+                    }
+                }
+            }
+        }
+        for (iface : dataClass.interfaces) {
+            val ret = getContextInstance(iface);
+            if (ret != null) return ret;
+        }
+        return null;
+    }
+
+    private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
+        for (method : source.methods) {
+            if (method.declaringClass == source) {
+                val redeclaredMethod = new CtMethod(method, target, null);
+                function1.process(redeclaredMethod);
+                target.addMethod(redeclaredMethod);
+            }
+        }
+    }
+
+    private def CtClass createClass(String fqn, ClassGenerator cls) {
+        val target = classPool.makeClass(fqn);
+        cls.process(target);
+        return target;
+    }
+
+    private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
+        val target = classPool.makeClass(fqn);
+        target.implementsType(superInterface);
+        cls.process(target);
+        return target;
+    }
+
+    private def void implementsType(CtClass it, CtClass supertype) {
+        checkArgument(supertype.interface, "Supertype must be interface");
+        addInterface(supertype);
+    }
+
+    private def asCtClass(Class<?> class1) {
+        classPool.get(class1);
+    }
+
+    private def CtField field(CtClass it, String name, Class<?> returnValue) {
+        val field = new CtField(returnValue.asCtClass, name, it);
+        field.modifiers = Modifier.PUBLIC
+        addField(field);
+        return field;
+    }
+
+    def get(ClassPool pool, Class<?> cls) {
+        try {
+            return pool.get(cls.name)
+        } catch (NotFoundException e) {
+            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
+            return pool.get(cls.name)
+        }
+    }
+}
index 2953466b2928a419eb0a2c3a09f4d74b771b7ab9..298a74ece5f71982ae7bcbb48f205e4039c44046 100644 (file)
@@ -11,30 +11,29 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
 import org.opendaylight.yangtools.yang.binding.RpcService
 import javassist.ClassPool
-import javassist.CtMethod
-import javassist.CtField
 import org.osgi.framework.BundleContext
 import java.util.Map
 import java.util.HashMap
 import javassist.LoaderClassPath
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
 import java.util.Hashtable
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
 
-import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.*
-import static extension org.opendaylight.controller.sal.binding.impl.utils.GeneratorUtils.*
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService
 import org.osgi.framework.ServiceRegistration
-import org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*
 import org.opendaylight.controller.sal.binding.api.NotificationService
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import javassist.Modifier
+
 import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator
 
 class BindingAwareBrokerImpl implements BindingAwareBroker {
-    private static val DELEGATE_FIELD = "_delegate"
     private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
     
     private val clsPool = ClassPool.getDefault()
+    private var RuntimeCodeGenerator generator;
     private Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new HashMap();
     private var NotificationBrokerImpl notifyBroker
     private var ServiceRegistration<NotificationProviderService> notifyBrokerRegistration
@@ -47,7 +46,7 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
 
         // Initialization of notificationBroker
         notifyBroker = new NotificationBrokerImpl(null);
-        val brokerProperties = PropertiesUtils.newProperties();
+        val brokerProperties = newProperties();
         notifyBrokerRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker,
             brokerProperties)
         brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties)
@@ -56,7 +55,8 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
     def initGenerator() {
 
         // YANG Binding Class Loader
-        clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader))
+        clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
+        generator = new RuntimeCodeGenerator(clsPool);
     }
 
     override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
@@ -97,35 +97,16 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
         if ((existing = managedProxies.get(service)) != null) {
             return existing.proxy
         }
-        val proxyClass = service.generateDirectProxy()
+        val proxyClass = generator.generateDirectProxy(service)
         val rpcProxyCtx = new RpcProxyContext(proxyClass)
         val properties = new Hashtable<String, String>()
         rpcProxyCtx.proxy = proxyClass.newInstance as RpcService
 
-        properties.salServiceType = Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY
+        properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY
         rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
         managedProxies.put(service, rpcProxyCtx)
         return rpcProxyCtx.proxy
     }
-
-    protected def generateDirectProxy(Class<? extends RpcService> delegate) {
-        val targetFqn = delegate.generatedName(Constants.PROXY_DIRECT_SUFFIX)
-        log.debug("Generating DirectProxy for {} Proxy name: {}",delegate,targetFqn);
-        val objCls = clsPool.get(Object)
-        val delegateCls = clsPool.get(delegate)
-        val proxyCls = clsPool.makeClass(targetFqn)
-        proxyCls.addInterface(delegateCls)
-        val delField = new CtField(delegateCls, DELEGATE_FIELD, proxyCls);
-        delField.modifiers = Modifier.PUBLIC
-        proxyCls.addField(delField)
-        delegateCls.methods.filter[it.declaringClass != objCls].forEach [
-            val proxyMethod = new CtMethod(it, proxyCls, null);
-            proxyMethod.body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
-            proxyCls.addMethod(proxyMethod)
-        ]
-        return proxyCls.toClass(delegate.classLoader)
-    }
-
     /**
      * Registers RPC Implementation
      * 
@@ -140,34 +121,4 @@ class BindingAwareBrokerImpl implements BindingAwareBroker {
         proxy.delegate = service;
         return new RpcServiceRegistrationImpl<T>(type, service, osgiReg);
     }
-    
-    /**
-     * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
-     * 
-     * Note: This method uses reflection, but access to delegate field should be 
-     * avoided and called only if neccessary.
-     * 
-     */
-    def <T extends RpcService> getDelegate(RpcService proxy) {
-        val field = proxy.class.getField(DELEGATE_FIELD)
-        if(field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
-        return field.get(proxy) as T
-    }
-    
-        /**
-     * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
-     * 
-     * Note: This method uses reflection, but setting delegate field should not occur too much
-     * to introduce any significant performance hits.
-     * 
-     */
-    def void setDelegate(RpcService proxy, RpcService delegate) {
-        val field = proxy.class.getField(DELEGATE_FIELD)
-        if(field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
-        if (field.type.isAssignableFrom(delegate.class)) {
-            field.set(proxy,delegate)
-        } else throw new IllegalArgumentException("delegate class is not assignable to proxy");
-    }
-    
-    
 }
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataProviderContext.xtend
new file mode 100644 (file)
index 0000000..398a219
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.impl
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
+
+class DataProviderContext {
+
+    @Property
+    var DataStoreIdentifier identifier;
+    @Property
+    var RuntimeDataProvider provider;
+}
index da1ba79997d16a910ccafe023076e72db460ae7c..22db73526e2e2e386636cc8b45320b3c246f24ad 100644 (file)
@@ -45,6 +45,7 @@ class NotificationBrokerImpl implements NotificationProviderService {
         notification.class.interfaces.filter[it != Notification && Notification.isAssignableFrom(it)]
     }
 
+    @SuppressWarnings("unchecked")
     def notifyAll(Collection<NotificationListener<?>> listeners, Notification notification) {
         listeners.forEach[(it as NotificationListener).onNotification(notification)]
     }
index a87fa0642a4eec5b33eca03630e2122f9d01ba61..a9031240c777961e9fdb5ad5bcb642b70c311f0a 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.controller.sal.binding.impl;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
@@ -7,47 +14,45 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.LoggerFactory
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
 
 class OsgiConsumerContext implements ConsumerContext {
 
-       static val log = LoggerFactory.getLogger(OsgiConsumerContext)
-       protected val BundleContext bundleContext;
-       protected val BindingAwareBrokerImpl broker;
-       
-       new(BundleContext ctx,BindingAwareBrokerImpl broker) {
-               this.bundleContext = ctx;
-               this.broker = broker;
-       }
-
-       
-       override def <T extends BindingAwareService> getSALService(Class<T> service) {
-               // SAL Services are global
-               var ref =  bundleContext.getServiceReference(service);
-               return bundleContext.getService(ref) as T;
-       }
-       
-       
-
-       override def <T extends RpcService> T getRpcService(Class<T> module) {
-               try {
-                       
-                       val services = bundleContext.getServiceReferences(module, getProxyFilter());
-                       
-                       // Proxy service found / using first implementation
-                       // FIXME: Add advanced logic to retrieve service with right set of models
-                       if(false == services.empty) {
-                               val ref = services.iterator().next() as ServiceReference<T>;
-                               return bundleContext.getService(ref) as T;
-                       } 
-               } catch (InvalidSyntaxException e) {
-                       log.error("Created filter was invalid:", e.message,e)
-               }
-               return null;
-               
-
-       }
-
-       private def getProxyFilter() {
-               return '''(«Constants.SAL_SERVICE_TYPE»=«Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY»)'''
-       }
+    static val log = LoggerFactory.getLogger(OsgiConsumerContext)
+    protected val BundleContext bundleContext;
+    protected val BindingAwareBrokerImpl broker;
+
+    new(BundleContext ctx, BindingAwareBrokerImpl broker) {
+        this.bundleContext = ctx;
+        this.broker = broker;
+    }
+
+    override def <T extends BindingAwareService> getSALService(Class<T> service) {
+
+        // SAL Services are global
+        var ref = bundleContext.getServiceReference(service);
+        return bundleContext.getService(ref) as T;
+    }
+
+    override def <T extends RpcService> T getRpcService(Class<T> module) {
+        try {
+
+            val services = bundleContext.getServiceReferences(module, getProxyFilter());
+
+            // Proxy service found / using first implementation
+            // FIXME: Add advanced logic to retrieve service with right set of models
+            if (false == services.empty) {
+                val ref = services.iterator().next() as ServiceReference<T>;
+                return bundleContext.getService(ref) as T;
+            }
+        } catch (InvalidSyntaxException e) {
+            log.error("Created filter was invalid:", e.message, e)
+        }
+        return null;
+
+    }
+
+    private def getProxyFilter() {
+        return '''(«SAL_SERVICE_TYPE»=«SAL_SERVICE_TYPE_CONSUMER_PROXY»)'''
+    }
 }
index 195fa8b9597ba19b5784e68e15d8d2fc563eef42..c769ca1ee38509fa3dbebd52948f81735fddf59c 100644 (file)
@@ -16,7 +16,8 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcService
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.osgi.framework.BundleContext;
 
-import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.*;
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*;
+import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*;
 
 class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext {
 
@@ -32,7 +33,7 @@ class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext
 
         // TODO Auto-generated method stub
         val properties = new Hashtable<String, String>();
-        properties.salServiceType = Constants.SAL_SERVICE_TYPE_PROVIDER
+        properties.salServiceType = SAL_SERVICE_TYPE_PROVIDER
 
         // Fill requirements
         val salReg = broker.registerRpcImplementation(type, implementation, this, properties)
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/_DataBrokerImpl.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/_DataBrokerImpl.xtend
new file mode 100644 (file)
index 0000000..b278df5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.impl
+
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
+import org.opendaylight.controller.sal.common.DataStoreIdentifier
+import org.opendaylight.yangtools.yang.binding.DataRoot
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService
+import org.opendaylight.controller.sal.binding.api.data.DataCommitHandler
+import org.opendaylight.controller.sal.binding.api.data.DataRefresher
+import org.opendaylight.controller.sal.binding.api.data.DataValidator
+import org.opendaylight.yangtools.yang.common.RpcResult
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
+import java.util.Map
+
+class _DataBrokerImpl implements DataProviderService {
+
+    Map<DataStoreIdentifier, DataProviderContext> dataProviders;
+    var DataProviderContext defaultDataProvider;
+
+    override <T extends DataRoot> getData(DataStoreIdentifier store, Class<T> rootType) {
+        val dataStore = resolveProvider(store, rootType);
+        return dataStore.provider.getData(store, rootType);
+    }
+
+    override <T extends DataRoot> getData(DataStoreIdentifier store, T filter) {
+    }
+
+    override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub");
+    }
+
+    override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub");
+    }
+
+    override commit(DataStoreIdentifier store) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override addRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override addValidator(DataStoreIdentifier store, DataValidator validator) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override removeRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    override removeCommitHandler(DataStoreIdentifier store, DataCommitHandler provider) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+
+    }
+
+    override removeValidator(DataStoreIdentifier store, DataValidator validator) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+    def DataProviderContext resolveProvider(DataStoreIdentifier store, Class<? extends DataRoot> root) {
+    }
+
+}
@@ -5,7 +5,7 @@
  * 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.impl
+package org.opendaylight.controller.sal.binding.impl.osgi
 
 class Constants {
 
@@ -16,6 +16,4 @@ class Constants {
     public static val SAL_SERVICE_TYPE_CONSUMER_PROXY = "consumerProxy"
     public static val SAL_SERVICE_TYPE_PROVIDER = "provider"
     public static val SAL_SERVICE_TYPE_CONNECTOR = "connector"
-
-    public static val PROXY_DIRECT_SUFFIX = "DirectProxy";
 }
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/PropertiesUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/PropertiesUtils.xtend
new file mode 100644 (file)
index 0000000..d04ca7f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.impl.osgi
+
+import java.util.Hashtable
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+
+class PropertiesUtils {
+
+    private new() {
+    }
+
+    static def setSalServiceType(Hashtable<String, String> properties, String value) {
+        properties.put(SAL_SERVICE_TYPE, value)
+        return properties
+    }
+
+    static def getSalServiceType(Hashtable<String, String> properties) {
+        return properties.get(SAL_SERVICE_TYPE)
+    }
+
+    static def newProperties() {
+        new Hashtable<String, String>()
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/osgi/package-info.java
new file mode 100644 (file)
index 0000000..d788ccf
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * 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.impl.osgi;
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/GeneratorUtils.xtend
deleted file mode 100644 (file)
index c888121..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl.utils
-
-import javassist.ClassPool
-import javassist.NotFoundException
-import javassist.LoaderClassPath
-
-class GeneratorUtils {
-
-    static val PREFIX = "_gen.";
-
-    public static def generatedName(Class<?> cls, String suffix) {
-        '''«PREFIX»«cls.package.name».«cls.simpleName»$«suffix»'''.toString()
-    }
-
-    public static def get(ClassPool pool, Class<?> cls) {
-        try {
-            return pool.get(cls.name)
-        } catch (NotFoundException e) {
-            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
-            return pool.get(cls.name)
-        }
-    }
-}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/PropertiesUtils.xtend
deleted file mode 100644 (file)
index 7ba62f5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl.utils
-
-import java.util.Hashtable
-import org.opendaylight.controller.sal.binding.impl.Constants
-
-class PropertiesUtils {
-       
-       private new() {}
-       
-       static def setSalServiceType(Hashtable<String,String> properties, String value) {
-               properties.put(Constants.SAL_SERVICE_TYPE,value)
-               return properties
-       }
-       
-       static def getSalServiceType(Hashtable<String,String> properties) {
-               return properties.get(Constants.SAL_SERVICE_TYPE)
-       }
-       
-       static def newProperties() {
-               new Hashtable<String,String>()
-       }
-       
-}
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/utils/package-info.java
deleted file mode 100644 (file)
index 5110238..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
-  *
-  * This program and the accompanying materials are made available under the
-  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
-  * and is available at http://www.eclipse.org/legal/epl-v10.html
-  */
-package org.opendaylight.controller.sal.binding.impl.utils;
\ No newline at end of file
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/test/org/opendaylight/controller/sal/binding/test/GenerationTest.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/test/org/opendaylight/controller/sal/binding/test/GenerationTest.java
new file mode 100644 (file)
index 0000000..9bbb501
--- /dev/null
@@ -0,0 +1,31 @@
+package org.opendaylight.controller.sal.binding.test;
+import static org.junit.Assert.*;
+
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.impl.ProxyFactoryGenerator;
+import org.opendaylight.controller.sal.binding.impl.RpcServiceProxy;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+
+public class GenerationTest {
+
+       public interface MockService extends RpcService {
+               
+           Future<RpcResult<java.lang.Void>> cancelToast();
+           
+           Future<RpcResult<java.lang.Void>> makeToast(String input);
+       }
+       
+       @Test
+       public void test() {
+               ProxyFactoryGenerator generator = new ProxyFactoryGenerator();
+               Class<? extends RpcServiceProxy<MockService>> ret = generator.generate(MockService.class);
+               
+               assertTrue(RpcServiceProxy.class.isAssignableFrom(ret));
+               assertTrue(MockService.class.isAssignableFrom(ret));
+       }
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java
new file mode 100644 (file)
index 0000000..5dddd1a
--- /dev/null
@@ -0,0 +1,142 @@
+package org.opendaylight.controller.sal.binding.test;
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javassist.ClassPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.test.mock.FooService;
+import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
+import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
+import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+import static org.mockito.Mockito.*;
+
+
+public class RuntimeCodeGeneratorTest {
+
+    private RuntimeCodeGenerator codeGenerator;
+
+    
+    @Before
+    public void initialize() {
+        this.codeGenerator = new RuntimeCodeGenerator(ClassPool.getDefault());
+    }
+    
+    @Test
+    public void testGenerateDirectProxy() {
+        Class<? extends FooService> product = codeGenerator.generateDirectProxy(FooService.class);
+        assertNotNull(product);
+    }
+
+    @Test
+    public void testGenerateRouter() throws Exception {
+        Class<? extends FooService> product = codeGenerator.generateRouter(FooService.class);
+        assertNotNull(product);
+        assertNotNull(product.getSimpleName());
+        assertEquals("2 fields should be generated.",2,product.getFields().length);
+        
+        verifyRouting(product.newInstance());
+    }
+
+    private void verifyRouting(FooService product) {
+        Map<InstanceIdentifier,FooService> routingTable = new HashMap<>();
+        setRoutingTable(product, BaseIdentity.class, routingTable);
+        
+        assertSame("Returned routing table should be same instance",routingTable,getRoutingTable(product, BaseIdentity.class));
+        
+        int servicesCount = 2;
+        int instancesPerService = 3;
+        
+        InstanceIdentifier[][] identifiers = identifiers(servicesCount,instancesPerService);
+        FooService service[] = new FooService[] {
+                mock(FooService.class, "Instance 0"),
+                mock(FooService.class,"Instance 1")
+        };
+        
+        for(int i = 0;i<service.length;i++) {
+            for (InstanceIdentifier instance : identifiers[i]) {
+                routingTable.put(instance, service[i]);
+            }
+        }
+        
+        assertEquals("All instances should be registered.", servicesCount*instancesPerService, routingTable.size());
+        
+        SimpleInput[] instance_0_input = new SimpleInputImpl[] {
+            new SimpleInputImpl(identifiers[0][0]),
+            new SimpleInputImpl(identifiers[0][1]),
+            new SimpleInputImpl(identifiers[0][2])
+        };
+        
+        SimpleInput[] instance_1_input = new SimpleInputImpl[] {
+                new SimpleInputImpl(identifiers[1][0]),
+                new SimpleInputImpl(identifiers[1][1]),
+                new SimpleInputImpl(identifiers[1][2])
+        };
+        
+        // We test sending mock messages
+        
+        product.simple(instance_0_input[0]);
+        verify(service[0]).simple(instance_0_input[0]);
+        
+        product.simple(instance_0_input[1]);
+        product.simple(instance_0_input[2]);
+        
+        verify(service[0]).simple(instance_0_input[1]);
+        verify(service[0]).simple(instance_0_input[2]);
+        
+        product.simple(instance_1_input[0]);
+        verify(service[1]).simple(instance_1_input[0]);
+    }
+
+    private InstanceIdentifier[][] identifiers(int serviceSize, int instancesPerService) {
+        InstanceIdentifier[][] ret = new InstanceIdentifier[serviceSize][];
+        int service = 0;
+        for (int i = 0;i<serviceSize;i++) {
+            
+            InstanceIdentifier[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
+            ret[i] = instanceIdentifiers;
+            for(int id = 0;id<instancesPerService;id++) {
+                instanceIdentifiers[id] = referencableIdentifier(service*instancesPerService+id);
+            }
+            service++;
+        }
+        
+        return ret;
+    }
+
+    private InstanceIdentifier referencableIdentifier(int i) {
+        ReferencableObjectKey key = new ReferencableObjectKey(i);
+        IdentifiableItem<ReferencableObject,ReferencableObjectKey> pathArg = new IdentifiableItem<>(ReferencableObject.class,key);
+        return new InstanceIdentifier(Arrays.<PathArgument>asList(pathArg), ReferencableObject.class);
+    }
+
+    private static class SimpleInputImpl implements SimpleInput {
+        private final InstanceIdentifier identifier;
+
+        public SimpleInputImpl(InstanceIdentifier _identifier) {
+            this.identifier = _identifier;
+        }
+
+        @Override
+        public <E extends Augmentation<SimpleInput>> E getAugmentation(Class<E> augmentationType) {
+            return null;
+        }
+
+        @Override
+        public InstanceIdentifier getIdentifier() {
+            return this.identifier;
+        }
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarUpdate.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarUpdate.java
new file mode 100644 (file)
index 0000000..b64ebdf
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface BarUpdate extends Grouping,Notification {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java
new file mode 100644 (file)
index 0000000..3629689
--- /dev/null
@@ -0,0 +1,10 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+
+public interface FooListener extends NotificationListener {
+
+    void onFooUpdate(FooUpdate notification);
+    void onBarUpdate(BarUpdate notification);
+    
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java
new file mode 100644 (file)
index 0000000..3161e93
--- /dev/null
@@ -0,0 +1,16 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface FooService extends RpcService {
+    
+    Future<RpcResult<Void>> foo();
+    
+    Future<RpcResult<Void>> simple(SimpleInput obj);
+    
+    Future<RpcResult<Void>> inheritedContextInput(InheritedContextInput obj);
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooUpdate.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooUpdate.java
new file mode 100644 (file)
index 0000000..a5a5eb8
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface FooUpdate extends Notification {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/Grouping.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/Grouping.java
new file mode 100644 (file)
index 0000000..86624e0
--- /dev/null
@@ -0,0 +1,11 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+
+public interface Grouping {
+
+    @RoutingContext(BaseIdentity.class)
+    InstanceIdentifier getInheritedIdentifier();
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/InheritedContextInput.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/InheritedContextInput.java
new file mode 100644 (file)
index 0000000..39b20cc
--- /dev/null
@@ -0,0 +1,5 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+public interface InheritedContextInput extends Grouping {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObject.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObject.java
new file mode 100644 (file)
index 0000000..8e0d457
--- /dev/null
@@ -0,0 +1,8 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+
+public interface ReferencableObject extends DataObject,Identifiable<ReferencableObjectKey> {
+
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java
new file mode 100644 (file)
index 0000000..d2e1817
--- /dev/null
@@ -0,0 +1,44 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+public class ReferencableObjectKey implements Identifier<ReferencableObject> {
+
+    final Integer value;
+    
+    public ReferencableObjectKey(Integer _value) {
+        this.value = _value;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ReferencableObjectKey other = (ReferencableObjectKey) obj;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "ReferencableObjectKey [value=" + value + "]";
+    }
+    
+    
+}
diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/SimpleInput.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/test/java/org/opendaylight/controller/sal/binding/test/mock/SimpleInput.java
new file mode 100644 (file)
index 0000000..dedbd98
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+
+public interface SimpleInput extends DataObject,Augmentable<SimpleInput> {
+
+    @RoutingContext(BaseIdentity.class)
+    InstanceIdentifier getIdentifier();
+}