From: Tony Tkacik Date: Fri, 5 Apr 2013 12:59:46 +0000 (+0200) Subject: Added support for RPCs to Binding-Aware SAL X-Git-Tag: releasepom-0.1.0~593 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=517b29d7abee88c4c99b3f75866c6a8e4b8fbd5d Added support for RPCs to Binding-Aware SAL Added support for RPCs to Binding-Aware SAL. The implementations of the RPCs are mapped to interfaces describing RPC contract. The registered implementation is registered for all RPCs described in the interface and only one registered implementation of the interface could exists at-the time. It is possible to register implementation of derived interface, but client must request the derived interface to access its implementation of rpcs defined in super interface. Signed-off-by: Tony Tkacik --- diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataProviderService.java b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataProviderService.java index e4e7be5c6c..8f90ddbbea 100644 --- a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataProviderService.java +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataProviderService.java @@ -62,24 +62,6 @@ public interface DataProviderService extends DataBrokerService { * @param store * @param refresher */ - void removeRefresher(DataStoreIdentifier store, DataRefresher refresher); - - /** - * Trigger for refreshing of the data exposed by the {@link Provider} - * - - * - */ - public interface DataRefresher extends - BindingAwareProvider.ProviderFunctionality { - - /** - * Fired when some component explicitly requested the data refresh. - * - * The provider which exposed the {@link DataRefresher} should republish - * its provided data by editing the data in all affected data stores. - */ - void refreshData(); - } + void removeRefresher(DataStoreIdentifier store, DataRefresher refresher); } diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataRefresher.java b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataRefresher.java index 56b2a9f4da..0f9997651f 100644 --- a/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataRefresher.java +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/DataRefresher.java @@ -7,9 +7,20 @@ */ package org.opendaylight.controller.sal.binding.api; -import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; - -public interface DataRefresher extends ProviderFunctionality { +/** + * Trigger for refreshing of the data exposed by the {@link Provider} + * + * + * + */ +public interface DataRefresher extends + BindingAwareProvider.ProviderFunctionality { + /** + * Fired when some component explicitly requested the data refresh. + * + * The provider which exposed the {@link DataRefresher} should republish its + * provided data by editing the data in all affected data stores. + */ void refreshData(); -} +} \ No newline at end of file diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml index f126744652..2d427cb61f 100644 --- a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/pom.xml @@ -11,6 +11,11 @@ + + org.opendaylight.controller + sal-common-util + 1.0-SNAPSHOT + org.opendaylight.controller sal-binding-api diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java index 2209f84cac..32eff18d4a 100644 --- a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingBrokerImpl.java @@ -7,17 +7,36 @@ */ package org.opendaylight.controller.sal.binding.impl; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareService; +import org.opendaylight.controller.sal.binding.spi.Mapper; +import org.opendaylight.controller.sal.binding.spi.MappingProvider; +import org.opendaylight.controller.sal.binding.spi.RpcMapper; +import org.opendaylight.controller.sal.binding.spi.RpcMapper.RpcProxyInvocationHandler; import org.opendaylight.controller.sal.binding.spi.SALBindingModule; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.yang.binding.DataObject; import org.opendaylight.controller.yang.binding.RpcService; +import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.common.RpcResult; +import org.opendaylight.controller.yang.data.api.CompositeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +50,22 @@ public class BindingBrokerImpl implements BindingAwareBroker { private Set modules = new HashSet(); private Map, SALBindingModule> salServiceProviders = new HashMap, SALBindingModule>(); + private MappingProvider mapping; + private BIFacade biFacade = new BIFacade(); + private org.opendaylight.controller.sal.core.api.Broker.ProviderSession biSession; + private ExecutorService executor; + + Map, RpcService> rpcImpls = Collections + .synchronizedMap(new HashMap, RpcService>()); + + private RpcProxyInvocationHandler rpcProxyHandler = new RpcProxyInvocationHandler() { + + @Override + public Future> invokeRpc( + RpcService proxy, QName rpc, DataObject input) { + return rpcProxyInvoked(proxy, rpc, input); + } + }; @Override public ConsumerSession registerConsumer(BindingAwareConsumer consumer) { @@ -41,9 +76,7 @@ public class BindingBrokerImpl implements BindingAwareBroker { consumer.onSessionInitialized(session); sessions.add(session); - return session; - } @Override @@ -116,11 +149,101 @@ public class BindingBrokerImpl implements BindingAwareBroker { } + private T newRpcProxyForSession(Class service) { + + RpcMapper mapper = mapping.rpcMapperForClass(service); + if (mapper == null) { + log.error("Mapper for " + service + "is unavailable."); + return null; + } + T proxy = mapper.getConsumerProxy(rpcProxyHandler); + + return proxy; + } + + private Future> rpcProxyInvoked( + RpcService rpcProxy, QName rpcType, DataObject inputData) { + if (rpcProxy == null) { + throw new IllegalArgumentException("Proxy must not be null"); + } + if (rpcType == null) { + throw new IllegalArgumentException( + "rpcType (QName) should not be null"); + } + Future> ret = null; + + // Real invocation starts here + RpcMapper mapper = mapping + .rpcMapperForProxy(rpcProxy); + RpcService impl = rpcImpls.get(mapper.getServiceClass()); + + if (impl == null) { + // RPC is probably remote + CompositeNode inputNode = null; + Mapper inputMapper = mapper.getInputMapper(); + if (inputMapper != null) { + inputNode = inputMapper.domFromObject(inputData); + } + Future> biResult = biSession.rpc(rpcType, + inputNode); + ret = new TranslatedFuture(biResult, mapper); + + } else { + // RPC is local + Callable> invocation = localRpcCallableFor( + impl, mapper, rpcType, inputData); + ret = executor.submit(invocation); + } + return ret; + } + + private Callable> localRpcCallableFor( + final RpcService impl, + final RpcMapper mapper, final QName rpcType, + final DataObject inputData) { + + return new Callable>() { + + @Override + public RpcResult call() throws Exception { + return mapper.invokeRpcImplementation(rpcType, impl, inputData); + } + }; + } + + // Binding Independent invocation of Binding Aware RPC + private RpcResult invokeLocalRpc(QName rpc, + CompositeNode inputNode) { + RpcMapper mapper = mapping.rpcMapperForData(rpc, + inputNode); + + DataObject inputTO = mapper.getInputMapper().objectFromDom(inputNode); + + RpcService impl = rpcImpls.get(mapper.getServiceClass()); + if (impl == null) { + log.warn("Implementation for rpc: " + rpc + "not available."); + } + RpcResult result = mapper + .invokeRpcImplementation(rpc, impl, inputTO); + DataObject outputTO = result.getResult(); + + CompositeNode outputNode = null; + if (outputTO != null) { + outputNode = mapper.getOutputMapper().domFromObject(outputTO); + } + return Rpcs.getRpcResult(result.isSuccessful(), outputNode, + result.getErrors()); + } + private class ConsumerSessionImpl implements BindingAwareBroker.ConsumerSession { private final BindingAwareConsumer consumer; - private Map, BindingAwareService> sessionSalServices = new HashMap, BindingAwareService>(); + private Map, BindingAwareService> sessionSalServices = Collections + .synchronizedMap(new HashMap, BindingAwareService>()); + + private Map, RpcService> sessionRpcProxies = Collections + .synchronizedMap(new HashMap, RpcService>()); public ConsumerSessionImpl(BindingAwareConsumer cons) { this.consumer = cons; @@ -153,9 +276,27 @@ public class BindingBrokerImpl implements BindingAwareBroker { } @Override - public T getRpcService(Class module) { - // TODO Implement this method - throw new UnsupportedOperationException("Not implemented"); + public T getRpcService(Class service) { + RpcService current = sessionRpcProxies.get(service); + if (current != null) { + if (service.isInstance(current)) { + @SuppressWarnings("unchecked") + T ret = (T) current; + return ret; + } else { + log.error("Proxy for rpc service " + service.getName() + + " does not implement the service interface"); + throw new IllegalStateException("Service implementation " + + current.getClass().getName() + + "does not implement " + service.getName()); + } + } else { + T ret = BindingBrokerImpl.this.newRpcProxyForSession(service); + if (ret != null) { + sessionRpcProxies.put(service, ret); + } + return ret; + } } public BindingAwareConsumer getConsumer() { @@ -176,12 +317,20 @@ public class BindingBrokerImpl implements BindingAwareBroker { @Override public void addRpcImplementation(RpcService implementation) { + if (implementation == null) { + throw new IllegalArgumentException( + "Implementation should not be null"); + } // TODO Implement this method throw new UnsupportedOperationException("Not implemented"); } @Override public void removeRpcImplementation(RpcService implementation) { + if (implementation == null) { + throw new IllegalArgumentException( + "Implementation should not be null"); + } // TODO Implement this method throw new UnsupportedOperationException("Not implemented"); } @@ -192,4 +341,96 @@ public class BindingBrokerImpl implements BindingAwareBroker { } + private class BIFacade implements Provider,RpcImplementation { + + @Override + public Set getSupportedRpcs() { + return Collections.emptySet(); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + if (rpc == null) { + throw new IllegalArgumentException( + "Rpc type should not be null"); + } + + return BindingBrokerImpl.this.invokeLocalRpc(rpc, input); + } + + @Override + public void onSessionInitiated( + org.opendaylight.controller.sal.core.api.Broker.ProviderSession session) { + + BindingBrokerImpl.this.biSession = session; + for (SALBindingModule module : modules) { + try { + module.onBISessionAvailable(biSession); + } catch(Exception e) { + log.error("Module " +module +" throwed unexpected exception",e); + } + } + } + + @Override + public Collection getProviderFunctionality() { + return Collections.emptySet(); + } + + } + + private static class TranslatedFuture implements + Future> { + private final Future> realFuture; + private final RpcMapper mapper; + + public TranslatedFuture(Future> future, + RpcMapper mapper) { + realFuture = future; + this.mapper = mapper; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return realFuture.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return realFuture.isCancelled(); + } + + @Override + public boolean isDone() { + return realFuture.isDone(); + } + + @Override + public RpcResult get() + throws InterruptedException, ExecutionException { + RpcResult val = realFuture.get(); + return tranlate(val); + } + + @Override + public RpcResult get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, + TimeoutException { + RpcResult val = realFuture.get(timeout, unit); + return tranlate(val); + } + + private RpcResult tranlate( + RpcResult result) { + CompositeNode outputNode = result.getResult(); + DataObject outputTO = null; + if (outputNode != null) { + Mapper outputMapper = mapper.getOutputMapper(); + outputTO = outputMapper.objectFromDom(outputNode); + } + return Rpcs.getRpcResult(result.isSuccessful(), outputTO, + result.getErrors()); + } + + } } diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java new file mode 100644 index 0000000000..cbd6b00570 --- /dev/null +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-broker-impl/src/main/java/org/opendaylight/controller/sal/binding/impl/DataModule.java @@ -0,0 +1,198 @@ +package org.opendaylight.controller.sal.binding.impl; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerSession; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; +import org.opendaylight.controller.sal.binding.api.BindingAwareService; +import org.opendaylight.controller.sal.binding.api.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.DataCommitHandler; +import org.opendaylight.controller.sal.binding.api.DataProviderService; +import org.opendaylight.controller.sal.binding.api.DataValidator; +import org.opendaylight.controller.sal.binding.spi.MappingProvider; +import org.opendaylight.controller.sal.binding.spi.SALBindingModule; +import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.controller.sal.binding.api.DataRefresher; +import org.opendaylight.controller.yang.binding.DataRoot; +import org.opendaylight.controller.yang.common.RpcResult; +import org.opendaylight.controller.yang.data.api.CompositeNode; + +public class DataModule implements SALBindingModule { + + private BindingAwareBroker broker; + private org.opendaylight.controller.sal.core.api.Broker.ProviderSession biSession; + private MappingProvider mappingProvider; + private final BIFacade biFacade = new BIFacade(); + private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; + + @Override + public void setBroker(BindingAwareBroker broker) { + this.broker = broker; + } + + @Override + public void onBISessionAvailable( + org.opendaylight.controller.sal.core.api.Broker.ProviderSession session) { + this.biSession = session; + this.biDataService = session + .getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class); + // biDataService.addRefresher(store, refresher) + + } + + @Override + public void setMappingProvider(MappingProvider provider) { + this.mappingProvider = provider; + + } + + @Override + public Set> getProvidedServices() { + Set> ret = new HashSet>(); + ret.add(DataBrokerService.class); + ret.add(DataProviderService.class); + return ret; + } + + @Override + public T getServiceForSession( + Class service, ConsumerSession session) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set> getSupportedProviderFunctionality() { + // TODO Auto-generated method stub + return null; + } + + private class DataBrokerSession implements DataBrokerService { + + @Override + public T getData(DataStoreIdentifier store, + Class rootType) { + // TODO Auto-generated method stub + return null; + } + + @Override + public T getData(DataStoreIdentifier store, + T filter) { + // TODO Auto-generated method stub + return null; + } + + @Override + public T getCandidateData( + DataStoreIdentifier store, Class rootType) { + // TODO Auto-generated method stub + return null; + } + + @Override + public T getCandidateData( + DataStoreIdentifier store, T filter) { + // TODO Auto-generated method stub + return null; + } + + @Override + public RpcResult editCandidateData(DataStoreIdentifier store, + DataRoot changeSet) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Future> commit(DataStoreIdentifier store) { + // TODO Auto-generated method stub + return null; + } + + } + + private class DataProviderSession extends DataBrokerSession implements + DataProviderService { + + @Override + public void addValidator(DataStoreIdentifier store, + DataValidator validator) { + // TODO Auto-generated method stub + + } + + @Override + public void removeValidator(DataStoreIdentifier store, + DataValidator validator) { + // TODO Auto-generated method stub + + } + + @Override + public void addCommitHandler(DataStoreIdentifier store, + DataCommitHandler provider) { + // TODO Auto-generated method stub + + } + + @Override + public void removeCommitHandler(DataStoreIdentifier store, + DataCommitHandler provider) { + // TODO Auto-generated method stub + + } + + @Override + public void addRefresher(DataStoreIdentifier store, + DataRefresher refresher) { + // TODO Auto-generated method stub + + } + + @Override + public void removeRefresher(DataStoreIdentifier store, + DataRefresher refresher) { + // TODO Auto-generated method stub + + } + + } + + private class BIFacade + implements + org.opendaylight.controller.sal.core.api.data.DataCommitHandler, + org.opendaylight.controller.sal.core.api.data.DataValidator, + org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher { + + @Override + public RpcResult validate(CompositeNode toValidate) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getSupportedDataStores() { + // TODO Auto-generated method stub + return null; + } + + @Override + public RpcResult requestCommit( + DataStoreIdentifier store) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void refreshData() { + // TODO Auto-generated method stub + + } + + } + +} diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/MappingProvider.java b/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/MappingProvider.java index a7fbb24089..b29eac2871 100644 --- a/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/MappingProvider.java +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/MappingProvider.java @@ -8,12 +8,40 @@ package org.opendaylight.controller.sal.binding.spi; import org.opendaylight.controller.yang.binding.DataObject; +import org.opendaylight.controller.yang.binding.RpcService; import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.data.api.CompositeNode; public interface MappingProvider { - Mapper getMapper(Class type); - Mapper getMapper(QName name); + Mapper mapperForClass(Class type); + Mapper mapperForQName(QName name); + + /** + * Returns {@link RpcMapper} associated to class + * + * @param type Class for which RpcMapper should provide mapping + * @return + */ + RpcMapper rpcMapperForClass(Class type); + + /** + * Returns {@link RpcMapper} associated to the {@link RpcService} proxy. + * + * @param proxy + * @return + */ + RpcMapper rpcMapperForProxy(RpcService proxy); + + /** + * + * + * @param rpc + * @param inputNode + * @return + */ + RpcMapper rpcMapperForData(QName rpc, + CompositeNode inputNode); MappingExtensionFactory getExtensionFactory(Class cls); @@ -25,4 +53,6 @@ public interface MappingProvider { T forClass(Class obj); } + + } diff --git a/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java b/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java new file mode 100644 index 0000000000..0db1bc2775 --- /dev/null +++ b/opendaylight/sal/yang-prototype/sal/sal-binding-spi/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcMapper.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.spi; + +import java.util.Set; +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.yang.binding.DataObject; +import org.opendaylight.controller.yang.binding.RpcService; +import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.common.RpcResult; + +public interface RpcMapper { + + Set getRpcQNames(); + + /** + * Returns a class object representing subinterface + * to whom, this mapper is assigned. + * + * @return + */ + Class getServiceClass(); + + /** + * Returns a Binding Mapper for Rpc Input Data + * @return + */ + Mapper getInputMapper(); + /** + * Returns a Binding Mapper for Rpc Output Data + * + * @return + */ + Mapper getOutputMapper(); + + /** + * Returns a consumer proxy, which is responsible + * for invoking the rpc functionality of {@link BindingAwareBroker} implementation. + * + * @return Proxy of {@link RpcService} assigned to this mapper. + */ + T getConsumerProxy(RpcProxyInvocationHandler handler); + + /** + * Invokes the method of RpcService representing the supplied rpc. + * + * @param rpc QName of Rpc + * @param impl Implementation of RpcService on which the method should be invoked + * @param baInput Input Data to RPC method + * @return Result of RPC invocation. + */ + RpcResult invokeRpcImplementation(QName rpc, + RpcService impl, DataObject baInput); + + public interface RpcProxyInvocationHandler { + + Future> invokeRpc(RpcService proxy, QName rpc, DataObject input); + } +}