--- /dev/null
+package org.opendaylight.controller.connectionmanager;
+
+public enum ConnectionLocality {
+ /**
+ * This controller is the (or one of the) master for a given node
+ */
+ LOCAL("This controller is the (or one of the) master for a given node"),
+
+ /**
+ * This controller is not the master for a given node
+ */
+ NOT_LOCAL("This controller is not the master for a given node"),
+
+ /**
+ * The given node is not connected to any of the controllers in the cluster
+ */
+ NOT_CONNECTED("The given node is not connected to any of the controllers in the cluster");
+
+ private ConnectionLocality(String description) {
+ this.description = description;
+ }
+
+ private String description;
+
+ public String toString() {
+ return description;
+ }
+}
public Set<Node> getLocalNodes();
/**
+ * @deprecated Use getLocalityStatus(Node node) instead.
+ *
* Method to test if a node is local to a controller.
*
- * @return true if node is local to this controller. false otherwise.
+ * @param node The node for which the locality is being tested
+ * @return true if node is local to this controller.<br>
+ * false if either node is not connected to this controller or
+ * not connected to any other controllers in the cluster.
*/
public boolean isLocal(Node node);
+ /**
+ * getLocalityStatus provides the tri-state connectivity status as opposed to the
+ * binary status returned by isLocal.
+ * ConnectionLocality enum that is returned by this method also includes the case of
+ * a Node not connected to any of the controllers in the cluster.
+ * @param node The node for which the locality is being verified
+ * @return ConnectionLocality
+ */
+ public ConnectionLocality getLocalityStatus(Node node);
+
/**
* Disconnect a Node from the controller.
*
import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
import org.opendaylight.controller.clustering.services.ICoordinatorChangeAware;
+import org.opendaylight.controller.connectionmanager.ConnectionLocality;
import org.opendaylight.controller.connectionmanager.ConnectionMgmtScheme;
import org.opendaylight.controller.connectionmanager.IConnectionManager;
import org.opendaylight.controller.connectionmanager.scheme.AbstractScheme;
return scheme.isLocal(node);
}
+ @Override
+ public ConnectionLocality getLocalityStatus(Node node) {
+ AbstractScheme scheme = schemes.get(activeScheme);
+ if (scheme == null) return ConnectionLocality.NOT_CONNECTED;
+ return scheme.getLocalityStatus(node);
+ }
+
@Override
public void updateNode(Node node, UpdateType type, Set<Property> props) {
logger.debug("updateNode: {} type {} props {}", node, type, props);
import org.opendaylight.controller.clustering.services.CacheExistException;
import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.connectionmanager.ConnectionLocality;
import org.opendaylight.controller.connectionmanager.ConnectionMgmtScheme;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.utils.Status;
return (controllers != null && controllers.contains(myController));
}
+ public ConnectionLocality getLocalityStatus(Node node) {
+ if (nodeConnections == null) return ConnectionLocality.NOT_CONNECTED;
+ Set<InetAddress> controllers = nodeConnections.get(node);
+ if (controllers == null || controllers.size() == 0) return ConnectionLocality.NOT_CONNECTED;
+ InetAddress myController = clusterServices.getMyAddress();
+ return controllers.contains(myController) ? ConnectionLocality.LOCAL:
+ ConnectionLocality.NOT_LOCAL;
+ }
+
public Status removeNode (Node node) {
return removeNodeFromController(node, clusterServices.getMyAddress());
}
import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.clustering.services.IClusterServices;
import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.connectionmanager.ConnectionLocality;
import org.opendaylight.controller.connectionmanager.IConnectionManager;
import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
}
Node n = e.getNode();
- if (!connectionManager.isLocal(n)) {
+ if (connectionManager.getLocalityStatus(n) == ConnectionLocality.NOT_LOCAL) {
Callable<Future<Status>> worker = new DistributeOrderCallable(e, u, t);
if (worker != null) {
Future<Future<Status>> workerRes = this.executor.submit(worker);
}
}
- logsync.trace("LOCAL Node {} so processing Entry:{} UpdateType:{}", n, e, t);
+ logsync.trace("Node {} could be local. so processing Entry:{} UpdateType:{}", n, e, t);
return null;
}
return;
}
Node n = fei.getNode();
- if (connectionManager.isLocal(n)) {
+ if (connectionManager.getLocalityStatus(n) == ConnectionLocality.LOCAL) {
logsync.trace("workOrder for fe {} processed locally", fe);
// I'm the controller in charge for the request, queue it for
// processing
org.osgi.service.packageadmin,
org.osgi.util.tracker,
javax.servlet.http,
+ org.codehaus.jackson,
org.codehaus.jackson.jaxrs,
+ org.codehaus.jackson.map,
org.slf4j
</Import-Package>
</instructions>
--- /dev/null
+/**
+ * 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.northbound.commons;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.codehaus.jackson.JsonProcessingException;
+
+/**
+ * A custom exception mapper for handling Jackson JsonProcessingException types
+ */
+@Provider
+@Consumes({MediaType.APPLICATION_JSON, "text/json"})
+public class JacksonJsonProcessingExceptionMapper
+ implements ExceptionMapper<JsonProcessingException>
+{
+
+ @Override
+ public Response toResponse(JsonProcessingException exception) {
+ GenericEntity<String> entity =
+ new GenericEntity<String>(exception.getMessage()) {};
+ return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
+ }
+}
+
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
+import org.codehaus.jackson.map.DeserializationConfig;
import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
}
} );
- singletons.add(new JacksonJaxbJsonProvider());
+ singletons.add(getJsonProvider());
+ singletons.add(new JacksonJsonProcessingExceptionMapper());
return singletons;
}
return result;
}
+ private static final JacksonJaxbJsonProvider getJsonProvider() {
+ JacksonJaxbJsonProvider jsonProvider = new JacksonJaxbJsonProvider();
+ jsonProvider.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,
+ false);
+ return jsonProvider;
+ }
+
private BundleContext getBundleContext() {
ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
Bundle bundle = null;
// Test GET deleted subnet1
result = getJsonResult(baseURL + "default/subnet/" + name1);
Assert.assertEquals(404, httpResponseCode.intValue());
+
+ // TEST PUT bad subnet, expect 400, validate JSON exception mapper
+ JSONObject joBad = new JSONObject().put("foo", "bar");
+ result = getJsonResult(baseURL + "default/subnet/foo", "PUT", joBad.toString());
+ Assert.assertEquals(400, httpResponseCode.intValue());
}
@Test
--- /dev/null
+module opendaylight-group-types {
+ namespace "urn:opendaylight:group:types";
+ prefix group;
+
+ import ietf-inet-types {prefix inet;}
+ import ietf-yang-types {prefix yang;}
+ import opendaylight-flow-types {prefix flow-types;}
+
+ revision "2013-09-17" {
+ description "Initial revision of group service";
+ }
+
+ typedef group-ref {
+ type instance-identifier;
+ }
+
+ grouping group-types {
+ leaf group-type {
+ type enumeration {
+ enum group-all;
+ enum group_select;
+ enum group_indirect;
+ enum group_ff;
+ }
+ }
+ }
+
+ grouping group {
+
+ uses group-types;
+
+ leaf group-id {
+ type group-ref;
+ }
+
+ container buckets {
+ list bucket {
+ key "order";
+ leaf order {
+ type int32;
+ }
+
+ leaf weight {
+ type uint16;
+ }
+
+ leaf watch_port {
+ type uint32;
+ }
+
+ leaf watch_group {
+ type uint32;
+ }
+
+ container actions {
+ list action {
+ key "action-order";
+ leaf action-order {
+ type int32;
+ }
+
+ uses flow-types:action;
+ }
+ }
+ }
+ }
+ }
+
+ grouping group-statistics-request {
+ list group-stats {
+ key "group-id";
+
+ leaf group-id {
+ type int32;
+ }
+ }
+ }
+
+ grouping group-statistics {
+
+ leaf group-id {
+ type int32;
+ }
+
+ leaf ref-count {
+ type yang:counter32;
+ }
+
+ leaf packet-count {
+ type yang:counter64;
+ }
+
+ leaf byte-count {
+ type yang:counter64;
+ }
+
+ container duration {
+ leaf second {
+ type yang:counter32;
+ }
+ leaf nanosecond {
+ type yang:counter32;
+ }
+ }
+
+ container buckets {
+ list bucket-counter {
+ key "order";
+ leaf order {
+ type int32;
+ }
+
+ leaf packet-count {
+ type yang:counter64;
+ }
+
+ leaf byte-count {
+ type yang:counter64;
+ }
+ }
+ }
+ }
+
+ grouping group-statistics-reply {
+ list group-stats {
+ key "group-stats-order";
+ leaf group-stats-order {
+ type int32;
+ }
+
+ uses group-statistics;
+ }
+ }
+
+ grouping group-desc-stats {
+ list group-desc-stats {
+ key "order-id";
+
+ leaf order-id {
+ type int32;
+ }
+
+ uses group;
+ }
+ }
+
+ grouping group-features {
+ list group-features {
+ key "order";
+ leaf order {
+ type int32;
+ }
+
+ uses group-types;
+ type capabilities {
+ enum select-weight;
+ enum select-liveness;
+ enum chaining;
+ enum chaining-checks;
+ }
+
+ leaf-list max-groups {
+ type uint32;
+ description "Maximum number of groups for each type";
+ max-elements 4;
+ }
+
+ leaf-list actions {
+ type uint32;
+ description "Bitmap number OFPAT_* that are supported";
+ max-elements 4;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module sal-group {
+ namespace "urn:opendaylight:group:service";
+ prefix group;
+
+ import yang-ext {prefix ext;}
+ import opendaylight-inventory {prefix inv;}
+ import ietf-inet-types {prefix inet;}
+ import opendaylight-group-types {prefix group-type;}
+
+ revision "2013-09-17" {
+ description "Initial revision of group service";
+ }
+
+ grouping node-group {
+ leaf node {
+ type inv:node-ref;
+ }
+
+ uses group-type:group;
+ }
+
+ /** Base configuration structure **/
+ grouping group-update {
+ container original-group {
+ uses group-type:group;
+ }
+ container updated-group {
+ uses group-type:group;
+ }
+ }
+
+ rpc add-group {
+ input {
+ uses node-group;
+ }
+ }
+
+ rpc remove-group {
+ input {
+ uses node-group;
+ }
+ }
+
+ rpc update-group {
+ input {
+ uses node-group;
+ }
+ }
+}
\ No newline at end of file
<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>
<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>
--- /dev/null
+/*
+ * 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);
+
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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))
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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)
+ }
+ }
+}
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
// 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)
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) {
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
*
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");
- }
-
-
}
--- /dev/null
+/*
+ * 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;
+}
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)]
}
+/*
+ * 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;
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»)'''
+ }
}
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 {
// 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)
--- /dev/null
+/*
+ * 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) {
+ }
+
+}
* 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 {
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";
}
--- /dev/null
+/*
+ * 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>()
+ }
+
+}
--- /dev/null
+/*
+ * 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
+++ /dev/null
-/*
- * 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)
- }
- }
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
--- /dev/null
+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));
+ }
+
+}
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface BarUpdate extends Grouping,Notification {
+
+}
--- /dev/null
+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);
+
+}
--- /dev/null
+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);
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface FooUpdate extends Notification {
+
+}
--- /dev/null
+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();
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+public interface InheritedContextInput extends Grouping {
+
+}
--- /dev/null
+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> {
+
+}
--- /dev/null
+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 + "]";
+ }
+
+
+}
--- /dev/null
+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();
+}