X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-binding-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fbinding%2Fimpl%2Fconnect%2Fdom%2FBindingIndependentConnector.java;h=7ec1f6512d27a165d878973c79668d679d7f3ee9;hp=daa3914cf73fd717c63cb2c3e251dc175ffe1191;hb=f2f7098e3678756d90a348cefc2b110757ce126a;hpb=9212fed678702583f4a555641208cf1c7b45b829 diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index daa3914cf7..7ec1f6512d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -1,13 +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.InvocationTargetException; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -18,24 +27,28 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; - import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; 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.api.routing.RouteChangePublisher; 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.spi.RpcContextIdentifier; -import org.opendaylight.controller.sal.binding.spi.RpcRouter; +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; @@ -49,23 +62,24 @@ import org.opendaylight.yangtools.yang.binding.BindingMapping; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.RpcInput; import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; 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 static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*; +import com.google.common.collect.ImmutableSet.Builder; +import com.google.common.util.concurrent.Futures; public class BindingIndependentConnector implements // RuntimeDataProvider, // @@ -74,11 +88,15 @@ public class BindingIndependentConnector implements // private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class); + @SuppressWarnings( "deprecation") private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier .builder().toInstance(); + private final static Method EQUALS_METHOD; + + private BindingIndependentMappingService mappingService; private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; @@ -96,7 +114,7 @@ public class BindingIndependentConnector implements // private Registration> biCommitHandlerRegistration; private RpcProvisionRegistry biRpcRegistry; - private RpcProviderRegistryImpl baRpcRegistry; + private RpcProviderRegistry baRpcRegistry; private ListenerRegistration domToBindingRpcManager; // private ListenerRegistration @@ -111,36 +129,59 @@ public class BindingIndependentConnector implements // }; + private Registration, DataObject>> baDataReaderRegistration; + + private boolean rpcForwarding = false; + + private boolean dataForwarding = false; + + 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 path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); - CompositeNode result = biDataService.readOperationalData(biPath); - Class targetType = path.getTargetType(); - - if (Augmentation.class.isAssignableFrom(targetType)) { - path = mappingService.fromDataDom(biPath); - Class> augmentType = (Class>) targetType; - DataObject parentTo = mappingService.dataObjectFromDataDom(path, result); - if (parentTo instanceof Augmentable) { - return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType); - } - - } - return mappingService.dataObjectFromDataDom(path, result); - + return potentialAugmentationRead(path, biPath, result); } catch (DeserializationException e) { throw new IllegalStateException(e); } } + private DataObject potentialAugmentationRead(InstanceIdentifier path, + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result) + throws DeserializationException { + Class targetType = path.getTargetType(); + if (Augmentation.class.isAssignableFrom(targetType)) { + path = mappingService.fromDataDom(biPath); + Class> augmentType = (Class>) targetType; + DataObject parentTo = mappingService.dataObjectFromDataDom(path, result); + if (parentTo instanceof Augmentable) { + return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType); + } + } + return mappingService.dataObjectFromDataDom(path, result); + } + @Override public DataObject readConfigurationData(InstanceIdentifier path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); CompositeNode result = biDataService.readConfigurationData(biPath); - return mappingService.dataObjectFromDataDom(path, result); + return potentialAugmentationRead(path, biPath, result); } catch (DeserializationException e) { throw new IllegalStateException(e); } @@ -149,25 +190,30 @@ public class BindingIndependentConnector implements // private DataModificationTransaction createBindingToDomTransaction( DataModification, DataObject> source) { DataModificationTransaction target = biDataService.beginTransaction(); + LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier()); for (Entry, DataObject> entry : source.getUpdatedConfigurationData() .entrySet()) { Entry biEntry = mappingService .toDataDom(entry); target.putConfigurationData(biEntry.getKey(), biEntry.getValue()); + LOG.debug("Update of Binding Configuration Data {} is translated to {}",entry,biEntry); } for (Entry, DataObject> entry : source.getUpdatedOperationalData() .entrySet()) { Entry biEntry = mappingService .toDataDom(entry); target.putOperationalData(biEntry.getKey(), biEntry.getValue()); + LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry); } for (InstanceIdentifier entry : source.getRemovedConfigurationData()) { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); target.removeConfigurationData(biEntry); + LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry); } for (InstanceIdentifier entry : source.getRemovedOperationalData()) { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); target.removeOperationalData(biEntry); + LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry); } return target; } @@ -222,7 +268,7 @@ public class BindingIndependentConnector implements // return biDataService; } - public void setBiDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) { + protected void setDomDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) { this.biDataService = biDataService; } @@ -230,7 +276,7 @@ public class BindingIndependentConnector implements // return baDataService; } - public void setBaDataService(DataProviderService baDataService) { + protected void setBindingDataService(DataProviderService baDataService) { this.baDataService = baDataService; } @@ -238,23 +284,40 @@ public class BindingIndependentConnector implements // return baRpcRegistry; } - public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) { + protected void setBindingRpcRegistry(RpcProviderRegistry rpcRegistry) { this.baRpcRegistry = rpcRegistry; } - public void start() { - baDataService.registerDataReader(ROOT, this); + public void startDataForwarding() { + checkState(!dataForwarding, "Connector is already forwarding data."); + baDataReaderRegistration = baDataService.registerDataReader(ROOT, this); baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler); biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler); baDataService.registerCommitHandlerListener(domToBindingCommitHandler); + dataForwarding = true; + } - if (baRpcRegistry != null && biRpcRegistry != null) { + public void startRpcForwarding() { + if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher) { + 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 setMappingService(BindingIndependentMappingService mappingService) { + public void startNotificationForwarding() { + checkState(!notificationForwarding, "Connector is already forwarding notifications."); + notificationForwarding = true; + } + + protected void setMappingService(BindingIndependentMappingService mappingService) { this.mappingService = mappingService; } @@ -265,8 +328,9 @@ public class BindingIndependentConnector implements // @Override public void onSessionInitiated(ProviderSession session) { - setBiDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class)); - start(); + setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class)); + setDomRpcRegistry(session.getService(RpcProvisionRegistry.class)); + } public void onRpcRouterCreated(Class serviceType, RpcRouter router) { @@ -381,7 +445,7 @@ public class BindingIndependentConnector implements // */ if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) { - return CommitHandlersTransactions.allwaysSuccessfulTransaction(bindingTransaction); + return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction); } DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction); BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction); @@ -420,7 +484,7 @@ public class BindingIndependentConnector implements // * duplicating data. */ if (domOpenedTransactions.containsKey(identifier)) { - return CommitHandlersTransactions.allwaysSuccessfulTransaction(domTransaction); + return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction); } org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction); @@ -431,10 +495,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> { + RouteChangeListener>, + RouterInstantiationListener { private final Map, 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 ctx = router.getContexts().iterator().next(); + getRpcForwarder(router.getServiceType(), ctx); + } @Override public void onRouteChange(RouteChange> change) { @@ -462,35 +548,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 supportedRpcs; private final WeakReference> rpcServiceType; private Set registrations; + private Map strategiesByQName = new HashMap<>(); + private WeakHashMap strategiesByMethod = new WeakHashMap<>(); public DomToBindingRpcForwarder(Class service) { this.rpcServiceType = new WeakReference>(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 service, Class context) { this.rpcServiceType = new WeakReference>(service); this.supportedRpcs = mappingService.getRpcQNamesFor(service); - registrations = new HashSet<>(); - for (QName rpc : supportedRpcs) { - registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this)); + Builder registrationsBuilder = ImmutableSet + . 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 context, Class service, @@ -504,6 +616,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 context, Class service, Set> set) { QName ctx = BindingReflections.findQName(context); @@ -520,6 +648,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 invokeRpc(QName rpc, CompositeNode domInput) { checkArgument(rpc != null); @@ -531,13 +671,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 rpcType) throws Exception { return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable() { @Override @@ -559,9 +703,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; @@ -576,11 +720,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> forwardToDomBroker(DataObject input); + public abstract RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception; @@ -597,9 +745,10 @@ public class BindingIndependentConnector implements // @SuppressWarnings("rawtypes") private WeakReference outputClass; - public DefaultInvocationStrategy(Method targetMethod, Class outputClass, + @SuppressWarnings({ "rawtypes", "unchecked" }) + public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class outputClass, Class inputClass) { - super(targetMethod); + super(rpc,targetMethod); this.outputClass = new WeakReference(outputClass); this.inputClass = new WeakReference(inputClass); } @@ -614,20 +763,58 @@ public class BindingIndependentConnector implements // RpcResult bindingResult = result.get(); return Rpcs.getRpcResult(true); } + + @Override + public Future> forwardToDomBroker(DataObject input) { + if(biRouter != null) { + CompositeNode xml = mappingService.toDataDom(input); + CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.>of(xml)); + RpcResult 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.>immediateFuture(baResult); + } + return Futures.>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 uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + @SuppressWarnings("unchecked") Future> result = (Future>) targetMethod.invoke(rpcService); RpcResult bindingResult = result.get(); return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors()); } + + @Override + public Future> forwardToDomBroker(DataObject input) { + return Futures.immediateFuture(null); + } + } + + public boolean isRpcForwarding() { + return rpcForwarding; + } + + public boolean isDataForwarding() { + return dataForwarding; + } + + public boolean isNotificationForwarding() { + // TODO Auto-generated method stub + return notificationForwarding; + } + public BindingIndependentMappingService getMappingService() { + return mappingService; } }