Merge "More defensive RPC handling in DOM Broker"
authorEd Warnicke <eaw@cisco.com>
Wed, 22 Jan 2014 05:54:32 +0000 (05:54 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 22 Jan 2014 05:54:32 +0000 (05:54 +0000)
20 files changed:
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java
opendaylight/md-sal/sal-dom-broker/pom.xml
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/$ModuleInfo.java [deleted file]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend [deleted file]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaContextProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java

index 87a07369bd4ada1e0302ab46899dd2adb10cbb49..6dc91e014b5c2bab078a915984abc5f52d510f8b 100644 (file)
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-broker-impl</artifactId>
             <version>1.0-SNAPSHOT</version>
-            <scope>runtime</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
index d976a0cec9ac7e828b9877001d0847e4cc29dab9..4f994e5673a2c80896d8c5168af4d0c299ee7bcf 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.codegen.impl;
 
 import org.opendaylight.yangtools.yang.binding.RpcService;
@@ -5,6 +12,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcR
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -125,6 +133,7 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
     @Override
     public RpcRegistration<T> registerDefaultService(T service) {
         // TODO Auto-generated method stub
+        RuntimeCodeHelper.setDelegate(invocationProxy, service);
         return null;
     }
 
index 8773476caee9ee4fd01f7b75b3b128bb331e3edd..ffc72657f0e3ef406961738c6c3598ac044ecd9e 100644 (file)
@@ -1,5 +1,13 @@
+/*
+ * 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 java.util.EventListener;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.HashMap;
@@ -42,9 +50,10 @@ public class RpcProviderRegistryImpl implements //
     private final Map<Class<? extends RpcService>, RpcRouter<?>> rpcRouters = new WeakHashMap<>();
     private final ListenerRegistry<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> routeChangeListeners = ListenerRegistry
             .create();
+    private final ListenerRegistry<RouterInstantiationListener> routerInstantiationListener = ListenerRegistry.create();
 
     private final static Logger LOG = LoggerFactory.getLogger(RpcProviderRegistryImpl.class);
-    
+
     private final String name;
 
     public String getName() {
@@ -75,7 +84,7 @@ public class RpcProviderRegistryImpl implements //
         T publicProxy = getRpcService(type);
         RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
         checkState(currentDelegate == null, "Rpc service is already registered");
-        LOG.debug("Registering {} as global implementation of {} in {}",implementation,type.getSimpleName(),this);
+        LOG.debug("Registering {} as global implementation of {} in {}", implementation, type.getSimpleName(), this);
         RuntimeCodeHelper.setDelegate(publicProxy, implementation);
         return new RpcProxyRegistration<T>(type, implementation, this);
     }
@@ -89,46 +98,73 @@ public class RpcProviderRegistryImpl implements //
         if (potentialProxy != null) {
             return potentialProxy;
         }
-        synchronized(this) {
+        synchronized (this) {
             /**
-             * Potential proxy could be instantiated by other thread while we were
-             * waiting for the lock.
+             * Potential proxy could be instantiated by other thread while we
+             * were waiting for the lock.
              */
-            
+
             potentialProxy = (T) publicProxies.get(type);
             if (potentialProxy != null) {
                 return (T) potentialProxy;
             }
             T proxy = rpcFactory.getDirectProxyFor(type);
-            LOG.debug("Created {} as public proxy for {} in {}",proxy,type.getSimpleName(),this);
+            LOG.debug("Created {} as public proxy for {} in {}", proxy, type.getSimpleName(), this);
             publicProxies.put(type, proxy);
             return proxy;
         }
     }
 
-    private <T extends RpcService> RpcRouter<T> getRpcRouter(Class<T> type) {
+    @SuppressWarnings("unchecked")
+    public <T extends RpcService> RpcRouter<T> getRpcRouter(Class<T> type) {
         RpcRouter<?> potentialRouter = rpcRouters.get(type);
         if (potentialRouter != null) {
             return (RpcRouter<T>) potentialRouter;
         }
-        synchronized(this) {
+        synchronized (this) {
             /**
-             * Potential Router could be instantiated by other thread while we were
-             * waiting for the lock.
+             * Potential Router could be instantiated by other thread while we
+             * were waiting for the lock.
              */
-            potentialRouter = rpcRouters.get(type); 
+            potentialRouter = rpcRouters.get(type);
             if (potentialRouter != null) {
                 return (RpcRouter<T>) potentialRouter;
             }
-            RpcRouter<T> router = rpcFactory.getRouterFor(type,name);
+            RpcRouter<T> router = rpcFactory.getRouterFor(type, name);
             router.registerRouteChangeListener(new RouteChangeForwarder(type));
-            LOG.debug("Registering router {} as global implementation of {} in {}",router,type.getSimpleName(),this);
+            LOG.debug("Registering router {} as global implementation of {} in {}", router, type.getSimpleName(), this);
             RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy());
             rpcRouters.put(type, router);
+            notifyListenersRoutedCreated(router);
             return router;
         }
     }
 
+    private void notifyListenersRoutedCreated(RpcRouter router) {
+
+        for (ListenerRegistration<RouterInstantiationListener> listener : routerInstantiationListener) {
+            try {
+                listener.getInstance().onRpcRouterCreated(router);
+            } catch (Exception e) {
+                LOG.error("Unhandled exception during invoking listener {}", e);
+            }
+        }
+
+    }
+
+    public ListenerRegistration<RouterInstantiationListener> registerRouterInstantiationListener(
+            RouterInstantiationListener listener) {
+        ListenerRegistration<RouterInstantiationListener> reg = routerInstantiationListener.register(listener);
+        try {
+            for (RpcRouter<?> router : rpcRouters.values()) {
+                listener.onRpcRouterCreated(router);
+            }
+        } catch (Exception e) {
+            LOG.error("Unhandled exception during invoking listener {}", e);
+        }
+        return reg;
+    }
+
     @Override
     public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
             L listener) {
@@ -143,6 +179,10 @@ public class RpcProviderRegistryImpl implements //
         this.rpcFactory = rpcFactory;
     }
 
+    public interface RouterInstantiationListener extends EventListener {
+        void onRpcRouterCreated(RpcRouter<?> router);
+    }
+
     private class RouteChangeForwarder<T extends RpcService> implements
             RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
 
index f200b4d08dc6c955b18ad5a04f639884db3f978a..72b96b22d1226a16f9bc0f76d5b56cebd107446b 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.connect.dom;
 
 import static com.google.common.base.Preconditions.checkNotNull;
index 75b0138e7cd75657adba42182d0dc7e0cf9c270c..7a7e086ec4c9098ca91e6a7897745eea688819e0 100644 (file)
@@ -1,10 +1,22 @@
+/*
+ * 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.connect.dom;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
 import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -28,13 +40,15 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublishe
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
 import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions;
 import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
@@ -54,15 +68,18 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-
-import static com.google.common.base.Preconditions.*;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.util.concurrent.Futures;
 
 public class BindingIndependentConnector implements //
         RuntimeDataProvider, //
@@ -71,11 +88,15 @@ public class BindingIndependentConnector implements //
 
     private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
 
+    @SuppressWarnings( "deprecation")
     private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
             .builder().toInstance();
 
+    private final static Method EQUALS_METHOD;
+    
+    
     private BindingIndependentMappingService mappingService;
 
     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
@@ -116,18 +137,33 @@ public class BindingIndependentConnector implements //
 
     private boolean notificationForwarding = false;
 
+    private RpcProviderRegistryImpl baRpcRegistryImpl;
+
+    private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
+    
+    
+    static {
+        try {
+        EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     @Override
     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
         try {
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
             CompositeNode result = biDataService.readOperationalData(biPath);
-            return potentialAugmentationRead(path,biPath,result);
+            return potentialAugmentationRead(path, biPath, result);
         } catch (DeserializationException e) {
             throw new IllegalStateException(e);
         }
     }
 
-    private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result) throws DeserializationException {
+    private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result)
+            throws DeserializationException {
         Class<? extends DataObject> targetType = path.getTargetType();
         if (Augmentation.class.isAssignableFrom(targetType)) {
             path = mappingService.fromDataDom(biPath);
@@ -145,7 +181,7 @@ public class BindingIndependentConnector implements //
         try {
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
             CompositeNode result = biDataService.readConfigurationData(biPath);
-            return potentialAugmentationRead(path,biPath,result);
+            return potentialAugmentationRead(path, biPath, result);
         } catch (DeserializationException e) {
             throw new IllegalStateException(e);
         }
@@ -255,15 +291,22 @@ public class BindingIndependentConnector implements //
         baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
         dataForwarding = true;
     }
-    
+
     public void startRpcForwarding() {
         if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
-            checkState(!rpcForwarding,"Connector is already forwarding RPCs");
+            checkState(!rpcForwarding, "Connector is already forwarding RPCs");
             domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
+            if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
+                baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
+                baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
+            }
+            if(biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
+                biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
+            }
             rpcForwarding = true;
         }
     }
-    
+
     public void startNotificationForwarding() {
         checkState(!notificationForwarding, "Connector is already forwarding notifications.");
         notificationForwarding = true;
@@ -282,7 +325,7 @@ public class BindingIndependentConnector implements //
     public void onSessionInitiated(ProviderSession session) {
         setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
         setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
-        
+
     }
 
     public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
@@ -447,10 +490,32 @@ public class BindingIndependentConnector implements //
         }
     }
 
+    /**
+     * Manager responsible for instantiating forwarders responsible for
+     * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
+     * 
+     */
     private class DomToBindingRpcForwardingManager implements
-            RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>> {
+            RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
+            RouterInstantiationListener {
 
         private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
+        private RpcProviderRegistryImpl registryImpl;
+
+        public RpcProviderRegistryImpl getRegistryImpl() {
+            return registryImpl;
+        }
+
+        public void setRegistryImpl(RpcProviderRegistryImpl registryImpl) {
+            this.registryImpl = registryImpl;
+        }
+        
+        
+        @Override
+        public void onRpcRouterCreated(RpcRouter<?> router) {
+            Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
+            getRpcForwarder(router.getServiceType(), ctx);
+        }
 
         @Override
         public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
@@ -478,35 +543,61 @@ public class BindingIndependentConnector implements //
             } else {
                 potential = new DomToBindingRpcForwarder(service, context);
             }
+
             forwarders.put(service, potential);
             return potential;
         }
 
     }
 
-    private class DomToBindingRpcForwarder implements RpcImplementation {
+    private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
 
         private final Set<QName> supportedRpcs;
         private final WeakReference<Class<? extends RpcService>> rpcServiceType;
         private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+        private Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
+        private WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
 
         public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
             this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
             this.supportedRpcs = mappingService.getRpcQNamesFor(service);
-            for (QName rpc : supportedRpcs) {
-                biRpcRegistry.addRpcImplementation(rpc, this);
+            try {
+                for (QName rpc : supportedRpcs) {
+                    RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
+                    strategiesByMethod.put(strategy.targetMethod, strategy);
+                    strategiesByQName.put(rpc, strategy);
+                    biRpcRegistry.addRpcImplementation(rpc, this);
+                }
+
+            } catch (Exception e) {
+                LOG.error("Could not forward Rpcs of type {}", service.getName());
             }
             registrations = ImmutableSet.of();
         }
 
+        /**
+         * Constructor for Routed RPC Forwareder.
+         * 
+         * @param service
+         * @param context
+         */
         public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
             this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
             this.supportedRpcs = mappingService.getRpcQNamesFor(service);
-            registrations = new HashSet<>();
-            for (QName rpc : supportedRpcs) {
-                registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
+            Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
+                    .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
+            try {
+                for (QName rpc : supportedRpcs) {
+                    RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
+                    strategiesByMethod.put(strategy.targetMethod, strategy);
+                    strategiesByQName.put(rpc, strategy);
+                    registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
+                }
+                createDefaultDomForwarder();
+            } catch (Exception e) {
+                LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
             }
-            registrations = ImmutableSet.copyOf(registrations);
+            registrations = registrationsBuilder.build();
         }
 
         public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
@@ -520,6 +611,22 @@ public class BindingIndependentConnector implements //
             }
         }
 
+        
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if(EQUALS_METHOD.equals(method)) {
+                return false;
+            }
+            RpcInvocationStrategy strategy = strategiesByMethod.get(method);
+            checkState(strategy != null);
+            checkArgument(args.length <= 2);
+            if(args.length == 1) {
+                checkArgument(args[0] instanceof DataObject);
+                return strategy.forwardToDomBroker((DataObject) args[0]);
+            }
+            return strategy.forwardToDomBroker(null);
+        }
+
         public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
                 Set<InstanceIdentifier<?>> set) {
             QName ctx = BindingReflections.findQName(context);
@@ -536,6 +643,18 @@ public class BindingIndependentConnector implements //
             return supportedRpcs;
         }
 
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        public void createDefaultDomForwarder() {
+            if (baRpcRegistryImpl != null) {
+                Class<?> cls = rpcServiceType.get();
+                ClassLoader clsLoader = cls.getClassLoader();
+                RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
+                
+                RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
+                rpcRouter.registerDefaultService(proxy);
+            }
+        }
+
         @Override
         public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
             checkArgument(rpc != null);
@@ -547,13 +666,17 @@ public class BindingIndependentConnector implements //
             checkState(rpcService != null);
             CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
             try {
-                return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput);
+                return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput);
             } catch (Exception e) {
                 throw new IllegalStateException(e);
             }
         }
 
-        private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc,
+        private RpcInvocationStrategy resolveInvocationStrategy(QName rpc) {
+            return strategiesByQName.get(rpc);
+        }
+
+        private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
                 final Class<? extends RpcService> rpcType) throws Exception {
             return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
                 @Override
@@ -575,9 +698,9 @@ public class BindingIndependentConnector implements //
                     RpcInvocationStrategy strategy = null;
                     if (outputClass.isPresent()) {
                         if (inputClass.isPresent()) {
-                            strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get());
+                            strategy = new DefaultInvocationStrategy(rpc,targetMethod, outputClass.get(), inputClass.get());
                         } else {
-                            strategy = new NoInputNoOutputInvocationStrategy(targetMethod);
+                            strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
                         }
                     } else {
                         strategy = null;
@@ -592,11 +715,15 @@ public class BindingIndependentConnector implements //
     private abstract class RpcInvocationStrategy {
 
         protected final Method targetMethod;
+        protected final QName rpc;
 
-        public RpcInvocationStrategy(Method targetMethod) {
+        public RpcInvocationStrategy(QName rpc,Method targetMethod) {
             this.targetMethod = targetMethod;
+            this.rpc = rpc;
         }
 
+        public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
+
         public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
                 throws Exception;
 
@@ -614,9 +741,9 @@ public class BindingIndependentConnector implements //
         private WeakReference<Class> outputClass;
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
-        public DefaultInvocationStrategy(Method targetMethod, Class<?> outputClass,
+        public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
                 Class<? extends DataContainer> inputClass) {
-            super(targetMethod);
+            super(rpc,targetMethod);
             this.outputClass = new WeakReference(outputClass);
             this.inputClass = new WeakReference(inputClass);
         }
@@ -631,13 +758,29 @@ public class BindingIndependentConnector implements //
             RpcResult<?> bindingResult = result.get();
             return Rpcs.getRpcResult(true);
         }
+        
+        @Override
+        public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
+            if(biRouter != null) { 
+                CompositeNode xml = mappingService.toDataDom(input);
+                CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
+                RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+                Object baResultValue = null;
+                if(result.getResult() != null) {
+                    baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
+                }
+                RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
+                return Futures.<RpcResult<?>>immediateFuture(baResult);
+            }
+            return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
+        }
 
     }
 
     private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
 
-        public NoInputNoOutputInvocationStrategy(Method targetMethod) {
-            super(targetMethod);
+        public NoInputNoOutputInvocationStrategy(QName rpc, Method targetMethod) {
+            super(rpc,targetMethod);
         }
 
         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
@@ -646,6 +789,11 @@ public class BindingIndependentConnector implements //
             RpcResult<Void> bindingResult = result.get();
             return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
         }
+        
+        @Override
+        public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
+            return Futures.immediateFuture(null);
+        }
     }
 
     public boolean isRpcForwarding() {
index c03d851f5c9ef740a14a9097feceaf8909833184..37a9c27d37a71b177668ad0724ead529c101b327 100644 (file)
@@ -36,8 +36,9 @@ import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
 import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -58,7 +59,7 @@ import com.google.common.util.concurrent.MoreExecutors;
 
 import static com.google.common.base.Preconditions.*;
 
-public class BindingTestContext implements AutoCloseable {
+public class BindingTestContext implements AutoCloseable, SchemaContextProvider {
 
     public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
             .builder().toInstance();
@@ -88,6 +89,12 @@ public class BindingTestContext implements AutoCloseable {
 
     private MountPointManagerImpl biMountImpl;
 
+    private SchemaContext schemaContext;
+
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
     protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) {
         this.executor = executor;
         this.classPool = classPool;
@@ -218,12 +225,12 @@ public class BindingTestContext implements AutoCloseable {
     }
 
     public void updateYangSchema(String[] files) {
-        SchemaContext context = getContext(files);
+        schemaContext = getContext(files);
         if (schemaAwareDataStore != null) {
-            schemaAwareDataStore.onGlobalContextUpdated(context);
+            schemaAwareDataStore.onGlobalContextUpdated(schemaContext);
         }
         if (mappingServiceImpl != null) {
-            mappingServiceImpl.onGlobalContextUpdated(context);
+            mappingServiceImpl.onGlobalContextUpdated(schemaContext);
         }
     }
 
@@ -275,7 +282,7 @@ public class BindingTestContext implements AutoCloseable {
         checkState(executor != null);
         biBrokerImpl = new BrokerImpl();
         biBrokerImpl.setExecutor(executor);
-        biBrokerImpl.setRouter(new RpcRouterImpl("test"));
+        biBrokerImpl.setRouter(new SchemaAwareRpcBroker("/", this));
     }
 
     public void startBindingNotificationBroker() {
index 92a0a3a98dab8e1075a893f0af0e6730992f56cc..b1547b66a763d690aee4aee76226bf9659d7ac53 100644 (file)
@@ -1,13 +1,25 @@
+/*
+ * 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.test.connect.dom;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertTrue;
+
 import java.math.BigInteger;
 import java.util.Collections;
+import java.util.Set;
 import java.util.concurrent.Future;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
 import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
@@ -19,19 +31,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddF
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -40,11 +47,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 
-import static junit.framework.Assert.*;
-
-import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.MoreExecutors;
 
@@ -60,6 +64,9 @@ public class CrossBrokerRpcTest {
     public static final NodeId NODE_B = new NodeId("b");
     public static final NodeId NODE_C = new NodeId("c");
     public static final NodeId NODE_D = new NodeId("d");
+    
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
 
     public static final InstanceIdentifier<Node> BA_NODE_A_ID = createBANodeIdentifier(NODE_A);
     public static final InstanceIdentifier<Node> BA_NODE_B_ID = createBANodeIdentifier(NODE_B);
@@ -71,10 +78,7 @@ public class CrossBrokerRpcTest {
     public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C);
     public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D);
 
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
-    private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
-    private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow");
-    private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow");
+    
 
     @Before
     public void setup() {
@@ -117,8 +121,29 @@ public class CrossBrokerRpcTest {
         assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next());
     }
 
-    public void bindingRpcInvoker_DomRoutedProviderTest() {
-
+    @Test
+    public void bindingRpcInvoker_DomRoutedProviderTest() throws Exception {
+        AddFlowOutputBuilder builder = new AddFlowOutputBuilder();
+        builder.setTransactionId(new TransactionId(BigInteger.valueOf(10)));
+        final AddFlowOutput output = builder.build();
+        org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration registration = biRpcRegistry.addRoutedRpcImplementation(ADD_FLOW_QNAME, new RpcImplementation() {
+            @Override
+            public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+                CompositeNode result = testContext.getBindingToDomMappingService().toDataDom(output);
+                return Rpcs.getRpcResult(true, result, ImmutableList.<RpcError>of());
+            }
+
+            @Override
+            public Set<QName> getSupportedRpcs() {
+                return ImmutableSet.of(ADD_FLOW_QNAME);
+            }
+        });
+        registration.registerPath(NodeContext.QNAME, BI_NODE_C_ID);
+        
+        SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
+        Future<RpcResult<AddFlowOutput>> baResult = baFlowInvoker.addFlow(addFlow(BA_NODE_C_ID).setPriority(500).build());
+        assertNotNull(baResult);
+        assertEquals(output,baResult.get().getResult());
     }
 
     private CompositeNode toDomRpcInput(DataObject addFlowA) {
index 951d5b142e76561485c5cd7f52e12fb84a462cce..faac6501c93c56a2bfbe7be90373faaead36e662 100644 (file)
@@ -1,10 +1,13 @@
 package org.opendaylight.controller.sal.core.api;
 
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-public interface RpcProvisionRegistry extends BrokerService {
+public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
 
     /**
      * Registers an implementation of the rpc.
@@ -28,6 +31,8 @@ public interface RpcProvisionRegistry extends BrokerService {
      */
     RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
             throws IllegalArgumentException;
+    
+    ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
 
     RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
 }
index 49b2f450a42840b3736963321bbcd9b9b75467e7..2ba5c4ba20377323f165542301d97153135df17b 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.core.api;
 
 import java.util.EventListener;
index 1680c1927707009a6dc3f147aa0a6bc9322aabdc..64195303e80b1ab6883acef8d12bd8c7940b501a 100644 (file)
@@ -5,14 +5,75 @@
  * 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.core.api;
 
+import java.io.Serializable;
+
+import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
 
-public interface RpcRoutingContext {
+public class RpcRoutingContext implements Immutable, Serializable {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -9079324728075883325L;
+    
+    private final QName context;
+    private final QName rpc;
+    
+    
+    private RpcRoutingContext(QName context, QName rpc) {
+        super();
+        this.context = context;
+        this.rpc = rpc;
+    }
+    
+    public static final RpcRoutingContext create(QName context, QName rpc) {
+        return new RpcRoutingContext(context, rpc);
+    }
+
+    public QName getContext() {
+        return context;
+    }
+
+    public QName getRpc() {
+        return rpc;
+    }
+
+    @Override
+    public String toString() {
+        return "RpcRoutingContext [context=" + context + ", rpc=" + rpc + "]";
+    }
 
-  public QName getContext();
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((context == null) ? 0 : context.hashCode());
+        result = prime * result + ((rpc == null) ? 0 : rpc.hashCode());
+        return result;
+    }
 
-  public QName getRpcType();
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        RpcRoutingContext other = (RpcRoutingContext) obj;
+        if (context == null) {
+            if (other.context != null)
+                return false;
+        } else if (!context.equals(other.context))
+            return false;
+        if (rpc == null) {
+            if (other.rpc != null)
+                return false;
+        } else if (!rpc.equals(other.rpc))
+            return false;
+        return true;
+    }
 }
index 949d59c49adbc984261cd24cfd1ec9681c468571..5c53f7685347ae57208ed1aca42a9b379920b05e 100644 (file)
                 <configuration>
                     <instructions>
                         <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Export-Package>
+                            org.opendaylight.controller.sal.dom.broker.spi
+                        </Export-Package>
                         <Private-Package>
-                            org.opendaylight.controller.sal.dom.broker.*,
-                            org.opendaylight.controller.config.yang.md.sal.dom.impl
+                            org.opendaylight.controller.sal.dom.broker,
+                            org.opendaylight.controller.sal.dom.broker.impl,
+                            org.opendaylight.controller.sal.dom.broker.osgi,
+                            org.opendaylight.controller.config.yang.md.sal.dom.impl,
+                            org.opendaylight.controller.config.yang.md.sal.dom.statistics,
+                            org.opendaylight.yangtools.yang.util
                         </Private-Package>
                         <Import-Package>
                             *
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/$ModuleInfo.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/$ModuleInfo.java
deleted file mode 100644 (file)
index 3cc5a61..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.opendaylight.controller.sal.dom.broker;
-
-public class $ModuleInfo {
-
-    
-}
index dc116ca9795537e9d97a7e8de7fac804cda8b041..3baae04019954d3ec7a9469d395b8b2a105aec0e 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.opendaylight.controller.sal.core.api.data.DataStore
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter
 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
-import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker
 
 class BrokerConfigActivator implements AutoCloseable {
     
@@ -38,13 +38,15 @@ class BrokerConfigActivator implements AutoCloseable {
         val emptyProperties = new Hashtable<String, String>();
         broker.setBundleContext(context);
         
-        broker.setRouter(new RpcRouterImpl("Rpc router"))
+        
         schemaService = new SchemaServiceImpl();
         schemaService.setContext(context);
         schemaService.setParser(new YangParserImpl());
         schemaService.start();
         schemaReg = context.registerService(SchemaService, schemaService, emptyProperties);
         
+        broker.setRouter(new SchemaAwareRpcBroker("/",schemaService));
+        
         dataService = new DataBrokerImpl();
         dataService.setExecutor(broker.getExecutor());
         
index 8f179987b9c769e9fb6bab288b4063f40bd3b873..4c84440c7ebb3e496472d523274efaabbd50d745 100644 (file)
@@ -31,6 +31,9 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
 import org.opendaylight.controller.sal.core.api.RpcImplementation
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 
 public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     private static val log = LoggerFactory.getLogger(BrokerImpl);
@@ -125,4 +128,12 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
         router.addRoutedRpcImplementation(rpcType,implementation);
     }
     
+    override addRpcRegistrationListener(RpcRegistrationListener listener) {
+        return router.addRpcRegistrationListener(listener);
+    }
+    
+    override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
+        return router.registerRouteChangeListener(listener);
+    }
+    
 }
index b4fccff3b0fe745ae71088942ed05e92429f5e0e..5a3e060a3c9a52a2c55b4876b283ec5559de63e5 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.dom.broker;
 
 import java.util.List;
@@ -8,34 +15,34 @@ import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
 import org.opendaylight.controller.sal.core.api.data.DataValidator;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
-import org.opendaylight.controller.sal.dom.broker.impl.DataReaderRouter;
 import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
-import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
 import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
-import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-public class MountPointImpl implements MountProvisionInstance {
+public class MountPointImpl implements MountProvisionInstance, SchemaContextProvider {
 
-    private final RpcRouter rpcs;
+    private final SchemaAwareRpcBroker rpcs;
     private final DataBrokerImpl dataReader;
     private final NotificationRouter notificationRouter;
     private final DataReader<InstanceIdentifier,CompositeNode> readWrapper;
@@ -47,7 +54,7 @@ public class MountPointImpl implements MountProvisionInstance {
 
     public MountPointImpl(InstanceIdentifier path) {
         this.mountPath = path;
-        rpcs = new RpcRouterImpl("");
+        rpcs = new SchemaAwareRpcBroker(path.toString(),this);
         dataReader = new DataBrokerImpl();
         notificationRouter = new NotificationRouterImpl();
         readWrapper = new ReadWrapper();
@@ -118,7 +125,6 @@ public class MountPointImpl implements MountProvisionInstance {
 
     @Override
     public Future<RpcResult<CompositeNode>> rpc(QName type, CompositeNode input) {
-        // TODO Auto-generated method stub
         return null;
     }
 
@@ -207,4 +213,10 @@ public class MountPointImpl implements MountProvisionInstance {
             RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
         return dataReader.registerCommitHandlerListener(commitHandlerListener);
     }
+
+    @Override
+    public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+            L listener) {
+        return rpcs.registerRouteChangeListener(listener);
+    }
 }
index a6c1c508aaa7327b7a008975dd50aa9c3b09ae9a..8afa1eeb5f0e475cfe65fb43936967a6f35bb0f3 100644 (file)
@@ -27,6 +27,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,6 +42,7 @@ import com.google.common.collect.Sets;
 import static com.google.common.base.Preconditions.*;
 
 public class SchemaServiceImpl implements //
+        SchemaContextProvider, //
         SchemaService, //
         ServiceTrackerCustomizer<SchemaServiceListener, SchemaServiceListener>, //
         AutoCloseable {
@@ -100,6 +102,12 @@ public class SchemaServiceImpl implements //
         listenerTracker.open();
     }
 
+    
+    @Override
+    public SchemaContext getSchemaContext() {
+        return getGlobalContext();
+    }
+    
     public SchemaContext getGlobalContext() {
         return getSchemaContextSnapshot();
     }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend
deleted file mode 100644 (file)
index 5ee19a0..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.opendaylight.controller.sal.dom.broker.impl
-
-import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
-import org.opendaylight.yangtools.concepts.Identifiable
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import static com.google.common.base.Preconditions.*;
-import java.util.Map
-import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration
-import java.util.concurrent.ConcurrentHashMap
-import java.util.Set
-import java.util.Collections
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
-import org.slf4j.LoggerFactory
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry
-import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-
-class RpcRouterImpl implements RpcRouter, Identifiable<String> {
-
-    static val log = LoggerFactory.getLogger(RpcRouterImpl)
-
-    Map<QName, RpcRegistration> implementations = new ConcurrentHashMap();
-
-    @Property
-    val Set<QName> supportedRpcs = Collections.unmodifiableSet(implementations.keySet);
-
-    private val rpcRegistrationListeners = new ListenerRegistry<RpcRegistrationListener>();
-
-    @Property
-    val String identifier;
-
-    new(String name) {
-        _identifier = name;
-    }
-
-    override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
-                checkNotNull(rpcType, "Rpc Type should not be null");
-        checkNotNull(implementation, "Implementation should not be null.");
-        val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this);
-        implementations.put(rpcType, reg)
-
-        for (listener : rpcRegistrationListeners.listeners) {
-            try {
-                listener.instance.onRpcImplementationAdded(rpcType);
-            } catch (Exception e) {
-                log.error("Unhandled exception during invoking listener", e);
-            }
-        }
-
-        return reg;
-    }
-
-    override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
-        checkNotNull(rpcType, "Rpc Type should not be null");
-        checkNotNull(implementation, "Implementation should not be null.");
-        checkState(!implementations.containsKey(rpcType), "Provider for supplied rpc is already registered.");
-        val reg = new RpcRegistrationImpl(rpcType, implementation, this);
-        implementations.put(rpcType, reg)
-
-        for (listener : rpcRegistrationListeners.listeners) {
-            try {
-                listener.instance.onRpcImplementationAdded(rpcType);
-            } catch (Exception e) {
-                log.error("Unhandled exception during invoking listener", e);
-            }
-        }
-
-        return reg;
-
-    }
-
-    override invokeRpc(QName rpc, CompositeNode input) {
-        checkNotNull(rpc, "Rpc Type should not be null");
-
-        val impl = implementations.get(rpc);
-        checkState(impl !== null, "Provider for supplied rpc is not registered.");
-
-        return impl.instance.invokeRpc(rpc, input);
-    }
-
-    def remove(RpcRegistrationImpl impl) {
-        val existing = implementations.get(impl.type);
-        if (existing == impl) {
-            implementations.remove(impl.type);
-        }
-        for (listener : rpcRegistrationListeners.listeners) {
-            try {
-                listener.instance.onRpcImplementationRemoved(impl.type);
-            } catch (Exception e) {
-                log.error("Unhandled exception during invoking listener", e);
-            }
-        }
-    }
-    
-    override addRpcRegistrationListener(RpcRegistrationListener listener) {
-        rpcRegistrationListeners.register(listener);
-    }
-
-}
-
-class RpcRegistrationImpl extends AbstractObjectRegistration<RpcImplementation> implements RpcRegistration {
-
-    @Property
-    val QName type;
-
-    @Property
-    var RpcRouterImpl router;
-
-    new(QName type, RpcImplementation instance, RpcRouterImpl router) {
-        super(instance)
-        _type = type
-        _router = router
-    }
-
-    override protected removeRegistration() {
-        router.remove(this);
-    }
-}
-class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration {
-
-
-    new(QName type, RpcImplementation instance, RpcRouterImpl router) {
-        super(type,instance,router)
-    }
-
-    override protected removeRegistration() {
-        router.remove(this);
-    }
-    override registerPath(QName context, InstanceIdentifier path) {
-        //
-        
-    }
-
-    override unregisterPath(QName context, InstanceIdentifier path) {
-        //
-    }
-}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java
new file mode 100644 (file)
index 0000000..de6cfa6
--- /dev/null
@@ -0,0 +1,426 @@
+package org.opendaylight.controller.sal.dom.broker.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+
+public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareRpcBroker.class);
+
+    private static final QName CONTEXT_REFERENCE = QName.create("urn:opendaylight:yang:extension:yang-ext",
+            "2013-07-09", "context-reference");
+    private final ListenerRegistry<RpcRegistrationListener> rpcRegistrationListeners = new ListenerRegistry<>();
+    private final ListenerRegistry<RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> routeChangeListeners = new ListenerRegistry<>();
+    
+
+    private final String identifier;
+    private final ConcurrentMap<QName, RpcImplementation> implementations = new ConcurrentHashMap<>();
+    private RpcImplementation defaultImplementation;
+    private SchemaContextProvider schemaProvider;
+
+    public SchemaAwareRpcBroker(String identifier, SchemaContextProvider schemaProvider) {
+        super();
+        this.identifier = identifier;
+        this.schemaProvider = schemaProvider;
+    }
+
+    public RpcImplementation getDefaultImplementation() {
+        return defaultImplementation;
+    }
+
+    public void setDefaultImplementation(RpcImplementation defaultImplementation) {
+        this.defaultImplementation = defaultImplementation;
+    }
+
+    public SchemaContextProvider getSchemaProvider() {
+        return schemaProvider;
+    }
+
+    public void setSchemaProvider(SchemaContextProvider schemaProvider) {
+        this.schemaProvider = schemaProvider;
+    }
+
+    @Override
+    public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+        checkArgument(rpcType != null, "RPC Type should not be null");
+        checkArgument(implementation != null, "RPC Implementatoin should not be null");
+        return getOrCreateRoutedRpcRouter(rpcType).addRoutedRpcImplementation(rpcType, implementation);
+    }
+
+    private RoutedRpcSelector getOrCreateRoutedRpcRouter(QName rpcType) {
+        RoutedRpcSelector potential = getRoutedRpcRouter(rpcType);
+        if (potential != null) {
+            return potential;
+        }
+        synchronized (implementations) {
+            potential = getRoutedRpcRouter(rpcType);
+            if (potential != null) {
+                return potential;
+            }
+            RpcDefinition definition = findRpcDefinition(rpcType);
+            RoutingStrategy strategy = getRoutingStrategy(definition);
+            checkState(strategy instanceof RoutedRpcStrategy, "Rpc %s is not routed.", rpcType);
+            potential = new RoutedRpcSelector((RoutedRpcStrategy) strategy, this);
+            implementations.put(rpcType, potential);
+            return potential;
+        }
+    }
+
+    private RoutedRpcSelector getRoutedRpcRouter(QName rpcType) {
+        RpcImplementation potential = implementations.get(rpcType);
+        if (potential != null) {
+            checkState(potential instanceof RoutedRpcSelector, "Rpc %s is not routed.", rpcType);
+            return (RoutedRpcSelector) potential;
+        }
+        return null;
+
+    }
+
+    @Override
+    public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
+            throws IllegalArgumentException {
+        checkArgument(rpcType != null, "RPC Type should not be null");
+        checkArgument(implementation != null, "RPC Implementatoin should not be null");
+        checkState(!hasRpcImplementation(rpcType), "Implementation already registered");
+        RpcDefinition definition = findRpcDefinition(rpcType);
+        checkArgument(!isRoutedRpc(definition), "RPC Type must not be routed.");
+        GlobalRpcRegistration reg = new GlobalRpcRegistration(rpcType, implementation, this);
+        return reg;
+    }
+
+    private boolean isRoutedRpc(RpcDefinition definition) {
+        return getRoutingStrategy(definition) instanceof RoutedRpcStrategy;
+    }
+
+    @Override
+    public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener) {
+        return rpcRegistrationListeners.register(listener);
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        return ImmutableSet.copyOf(implementations.keySet());
+    }
+
+    @Override
+    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+        return findRpcImplemention(rpc).invokeRpc(rpc, input);
+    }
+
+    private RpcImplementation findRpcImplemention(QName rpc) {
+        checkArgument(rpc != null, "Rpc name should not be null");
+        RpcImplementation potentialImpl = implementations.get(rpc);
+        if (potentialImpl != null) {
+            return potentialImpl;
+        }
+        potentialImpl = defaultImplementation;
+        checkState(potentialImpl != null, "Implementation is not available.");
+        return potentialImpl;
+    }
+
+    private boolean hasRpcImplementation(QName rpc) {
+        return implementations.containsKey(rpc);
+    }
+
+    private RpcDefinition findRpcDefinition(QName rpcType) {
+        checkArgument(rpcType != null, "Rpc name must be supplied.");
+        checkState(schemaProvider != null, "Schema Provider is not available.");
+        SchemaContext ctx = schemaProvider.getSchemaContext();
+        checkState(ctx != null, "YANG Schema Context is not available.");
+        Module module = ctx.findModuleByNamespaceAndRevision(rpcType.getNamespace(), rpcType.getRevision());
+        checkState(module != null, "YANG Module is not available.");
+        return findRpcDefinition(rpcType, module.getRpcs());
+    }
+
+    static private RpcDefinition findRpcDefinition(QName rpcType, Set<RpcDefinition> rpcs) {
+        checkState(rpcs != null, "Rpc schema is not available.");
+        for (RpcDefinition rpc : rpcs) {
+            if (rpcType.equals(rpc.getQName())) {
+                return rpc;
+            }
+        }
+        throw new IllegalArgumentException("Supplied Rpc Type is not defined.");
+    }
+
+    private RoutingStrategy getRoutingStrategy(RpcDefinition rpc) {
+        ContainerSchemaNode input = rpc.getInput();
+        if (input != null) {
+            for (DataSchemaNode schemaNode : input.getChildNodes()) {
+                Optional<QName> context = getRoutingContext(schemaNode);
+                if (context.isPresent()) {
+                    return createRoutedStrategy(rpc, context.get(), schemaNode.getQName());
+                }
+            }
+        }
+        return createGlobalStrategy(rpc);
+    }
+
+    private static RoutingStrategy createRoutedStrategy(RpcDefinition rpc, QName context, QName leafNode) {
+        return new RoutedRpcStrategy(rpc.getQName(), context, leafNode);
+    }
+
+    private Optional<QName> getRoutingContext(DataSchemaNode schemaNode) {
+        for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) {
+            if (CONTEXT_REFERENCE.equals(extension.getNodeType())) {
+                return Optional.fromNullable(extension.getQName());
+            }
+            ;
+        }
+        return Optional.absent();
+    }
+
+    private static RoutingStrategy createGlobalStrategy(RpcDefinition rpc) {
+        GlobalRpcStrategy ret = new GlobalRpcStrategy(rpc.getQName());
+        return ret;
+    }
+
+    private static abstract class RoutingStrategy implements Identifiable<QName> {
+
+        private final QName identifier;
+
+        public RoutingStrategy(QName identifier) {
+            super();
+            this.identifier = identifier;
+        }
+
+        @Override
+        public QName getIdentifier() {
+            return identifier;
+        }
+    }
+
+    private static class GlobalRpcStrategy extends RoutingStrategy {
+
+        public GlobalRpcStrategy(QName identifier) {
+            super(identifier);
+        }
+    }
+
+    private static class RoutedRpcStrategy extends RoutingStrategy {
+
+        private final QName context;
+        private final QName leaf;
+
+        public RoutedRpcStrategy(QName identifier, QName ctx, QName leaf) {
+            super(identifier);
+            this.context = ctx;
+            this.leaf = leaf;
+        }
+
+        public QName getContext() {
+            return context;
+        }
+
+        public QName getLeaf() {
+            return leaf;
+        }
+    }
+
+    private static class RoutedRpcSelector implements RpcImplementation, AutoCloseable, Identifiable<QName> {
+
+        private final RoutedRpcStrategy strategy;
+        private final Set<QName> supportedRpcs;
+        private RpcImplementation defaultDelegate;
+        private final ConcurrentMap<InstanceIdentifier, RoutedRpcRegImpl> implementations = new ConcurrentHashMap<>();
+        private SchemaAwareRpcBroker router;
+
+        public RoutedRpcSelector(RoutedRpcStrategy strategy, SchemaAwareRpcBroker router) {
+            super();
+            this.strategy = strategy;
+            supportedRpcs = ImmutableSet.of(strategy.getIdentifier());
+            this.router = router;
+        }
+
+        @Override
+        public QName getIdentifier() {
+            return strategy.getIdentifier();
+        }
+
+        @Override
+        public void close() throws Exception {
+
+        }
+
+        @Override
+        public Set<QName> getSupportedRpcs() {
+            return supportedRpcs;
+        }
+
+        public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+            return new RoutedRpcRegImpl(rpcType, implementation, this);
+        }
+
+        @Override
+        public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+            CompositeNode inputContainer = input.getFirstCompositeByName(QName.create(rpc,"input"));
+            checkArgument(inputContainer != null, "Rpc payload must contain input element");
+            SimpleNode<?> routeContainer = inputContainer.getFirstSimpleByName(strategy.getLeaf());
+            checkArgument(routeContainer != null, "Leaf %s must be set with value", strategy.getLeaf());
+            Object route = routeContainer.getValue();
+            RpcImplementation potential = null;
+            if (route != null) {
+                RoutedRpcRegImpl potentialReg = implementations.get(route);
+                if (potentialReg != null) {
+                    potential = potentialReg.getInstance();
+                }
+            }
+            if (potential == null) {
+                potential = defaultDelegate;
+            }
+            checkState(potential != null, "No implementation is available for rpc:%s path:%s", rpc, route);
+            return potential.invokeRpc(rpc, input);
+        }
+
+        public void addPath(QName context, InstanceIdentifier path, RoutedRpcRegImpl routedRpcRegImpl) {
+            //checkArgument(strategy.getContext().equals(context),"Supplied context is not supported.");
+            RoutedRpcRegImpl previous = implementations.put(path, routedRpcRegImpl);
+            if (previous == null) {
+                router.notifyPathAnnouncement(context,strategy.getIdentifier(), path);
+            }
+
+        }
+
+        public void removePath(QName context, InstanceIdentifier path, RoutedRpcRegImpl routedRpcRegImpl) {
+            boolean removed = implementations.remove(path, routedRpcRegImpl);
+            if (removed) {
+                router.notifyPathWithdrawal(context, strategy.getIdentifier(), path);
+            }
+        }
+    }
+
+    private static class GlobalRpcRegistration extends AbstractObjectRegistration<RpcImplementation> implements
+            RpcRegistration {
+        private final QName type;
+        private SchemaAwareRpcBroker router;
+
+        public GlobalRpcRegistration(QName type, RpcImplementation instance, SchemaAwareRpcBroker router) {
+            super(instance);
+            this.type = type;
+            this.router = router;
+        }
+
+        @Override
+        public QName getType() {
+            return type;
+        }
+
+        @Override
+        protected void removeRegistration() {
+            if (router != null) {
+                router.remove(this);
+                router = null;
+            }
+        }
+    }
+
+    private static class RoutedRpcRegImpl extends AbstractObjectRegistration<RpcImplementation> implements
+            RoutedRpcRegistration {
+
+        private final QName type;
+        private RoutedRpcSelector router;
+
+        public RoutedRpcRegImpl(QName rpcType, RpcImplementation implementation, RoutedRpcSelector routedRpcSelector) {
+            super(implementation);
+            this.type = rpcType;
+            router = routedRpcSelector;
+        }
+
+        @Override
+        public void registerPath(QName context, InstanceIdentifier path) {
+            router.addPath(context, path, this);
+        }
+
+        @Override
+        public void unregisterPath(QName context, InstanceIdentifier path) {
+            router.removePath(context, path, this);
+        }
+
+        @Override
+        protected void removeRegistration() {
+
+        }
+
+        @Override
+        public QName getType() {
+            return type;
+        }
+
+    }
+
+    private void remove(GlobalRpcRegistration registration) {
+        implementations.remove(registration.getType(), registration);
+    }
+
+    private void notifyPathAnnouncement(QName context, QName identifier, InstanceIdentifier path) {
+        RpcRoutingContext contextWrapped = RpcRoutingContext.create(context, identifier);
+        RouteChange<RpcRoutingContext, InstanceIdentifier> change = RoutingUtils.announcementChange(contextWrapped , path);
+        for(ListenerRegistration<RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> routeListener : routeChangeListeners) {
+            try {
+                routeListener.getInstance().onRouteChange(change);
+            } catch (Exception e) {
+                LOG.error("Unhandled exception during invoking onRouteChange for {}",routeListener.getInstance(),e);
+                
+            }
+        }
+        
+    }
+
+    
+
+    private void notifyPathWithdrawal(QName context,QName identifier, InstanceIdentifier path) {
+        RpcRoutingContext contextWrapped = RpcRoutingContext.create(context, identifier);
+        RouteChange<RpcRoutingContext, InstanceIdentifier> change = RoutingUtils.removalChange(contextWrapped , path);
+        for(ListenerRegistration<RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> routeListener : routeChangeListeners) {
+            try {
+                routeListener.getInstance().onRouteChange(change);
+            } catch (Exception e) {
+                LOG.error("Unhandled exception during invoking onRouteChange for {}",routeListener.getInstance(),e);
+            }
+        }
+    }
+    
+    @Override
+    public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+            L listener) {
+        return routeChangeListeners.registerWithType(listener);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaContextProvider.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaContextProvider.java
new file mode 100644 (file)
index 0000000..3cf9a5d
--- /dev/null
@@ -0,0 +1,11 @@
+package org.opendaylight.controller.sal.dom.broker.impl;
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.base.Optional;
+
+public interface SchemaContextProvider {
+
+    SchemaContext getSchemaContext();
+    
+}
index 6886f892c6c851af6cb4e6ed8053cb1b44750cb4..7ec8ce1d78bf795e94702ca8f12c61dbe8d3d60e 100644 (file)
@@ -26,6 +26,4 @@ public interface RpcRouter extends RpcProvisionRegistry, RpcImplementation {
     
     @Override
     public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
-
-    ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
 }