All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.opendaylight.jsonrpc.binding.SchemaAwareTransportFactory Maven / Gradle / Ivy
/*
* Copyright (c) 2018 Lumina Networks, Inc. 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.jsonrpc.binding;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.reflect.Reflection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.opendaylight.jsonrpc.bus.api.BusSessionFactoryProvider;
import org.opendaylight.jsonrpc.bus.messagelib.AbstractTransportFactory;
import org.opendaylight.jsonrpc.bus.messagelib.NoopReplyMessageHandler;
import org.opendaylight.jsonrpc.bus.messagelib.RequesterSession;
import org.opendaylight.jsonrpc.bus.messagelib.ResponderSession;
import org.opendaylight.jsonrpc.bus.messagelib.TransportFactory;
import org.opendaylight.jsonrpc.bus.spi.EventLoopConfiguration;
import org.opendaylight.jsonrpc.bus.spi.EventLoopGroupProvider;
import org.opendaylight.yangtools.concepts.ObjectRegistration;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link TransportFactory} capable of (de)serializing binding-generated objects.
*
* @author Richard Kosegi
* @since Sep 20, 2018
*/
public final class SchemaAwareTransportFactory extends AbstractTransportFactory {
private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareTransportFactory.class);
private final Map> proxyMap = new ConcurrentHashMap<>();
private final RpcInvocationAdapter invocationAdapter;
/**
* This constructor is not meant to be called directly, but via {@link Builder#build()}. Created instance is
* suitable in embedded applications.
*
* @param invocationAdapter instance of {@link RpcInvocationAdapter} used to process RPC
* @param eventLoopConfiguration {@link EventLoopConfiguration}
*/
private SchemaAwareTransportFactory(final RpcInvocationAdapter invocationAdapter,
EventLoopConfiguration eventLoopConfiguration) {
super(new EmbeddedBusSessionFactoryProvider(eventLoopConfiguration));
this.invocationAdapter = Objects.requireNonNull(invocationAdapter);
}
/**
* This constructor is meant to be used within controller context, primary in blueprint definition.
*
* @param invocationAdapter instance of {@link RpcInvocationAdapter} used to process RPC
* @param busSessionFactoryProvider custom {@link BusSessionFactoryProvider} instance
*/
public SchemaAwareTransportFactory(final ControllerRpcInvocationAdapter invocationAdapter,
BusSessionFactoryProvider busSessionFactoryProvider) {
super(busSessionFactoryProvider);
this.invocationAdapter = Objects.requireNonNull(invocationAdapter);
}
@SuppressWarnings({ "checkstyle:HiddenField", "squid:S2176" })
public static class Builder {
private EventLoopConfiguration eventLoopConfiguration;
private RpcInvocationAdapter rpcInvocationAdapter;
public Builder withRpcInvocationAdapter(RpcInvocationAdapter rpcInvocationAdapter) {
this.rpcInvocationAdapter = rpcInvocationAdapter;
return this;
}
public Builder withEventLoopConfig(EventLoopConfiguration eventLoopConfiguration) {
this.eventLoopConfiguration = eventLoopConfiguration;
return this;
}
public SchemaAwareTransportFactory build() {
if (eventLoopConfiguration == null) {
eventLoopConfiguration = EventLoopGroupProvider.config();
}
if (rpcInvocationAdapter == null) {
rpcInvocationAdapter = EmbeddedRpcInvocationAdapter.INSTANCE;
}
return new SchemaAwareTransportFactory(rpcInvocationAdapter, eventLoopConfiguration);
}
}
/**
* Create requester session against remote endpoint by creating proxy of given type.
*
* @param type Type of {@link RpcService} to create proxy for
* @param uri remote endpoint URI
* @return proxy for {@link RpcService}.
* @throws URISyntaxException if provided URI is invalid
*/
public ProxyContext createBindingRequesterProxy(Class type, String uri)
throws URISyntaxException {
LOG.info("Creating requester proxy for type {} against endpoint '{}'", type.getName(), uri);
final RequesterSession requester = createRequester(uri, NoopReplyMessageHandler.INSTANCE);
final OutboundHandler handler = new OutboundHandler<>(type, invocationAdapter, requester);
final T proxy = Reflection.newProxy(type, handler);
final ObjectRegistration rpcReg = invocationAdapter.registerImpl(type, proxy);
final ProxyContext context = new ProxyContext<>(type, rpcReg, requester, proxy, this::closeProxy);
proxyMap.put(proxy, context);
return context;
}
/**
* Create binding-aware requester proxy against remote responder endpoint implementing multiple service models.
*
* @param services set of {@link RpcService} implemented by remote service
* @param uri remote responder endpoint
* @return {@link MultiModelProxy} used to get actual RPC proxy and close requester once it is no longer needed
* @throws URISyntaxException if provided responder URI is invalid
*/
@SuppressWarnings("unchecked")
public MultiModelProxy createMultiModelRequesterProxy(Set> services, String uri)
throws URISyntaxException {
final Set> proxies = new HashSet<>();
for (final Class extends RpcService> service : services) {
proxies.add((ProxyContext) createBindingRequesterProxy(service, uri));
}
return new MultiModelProxy(proxies);
}
/**
* Closes proxy instance created by {@link #createRequesterProxy(Class, String)}.
*
* @param proxy proxy instance to close.
*/
private void closeProxy(Object proxy) {
final ProxyContext extends RpcService> context = proxyMap.remove(proxy);
if (context != null) {
context.closeInternal();
}
}
/**
* Create responder bound to local socket provided in URI.
*
* @param type actual {@link RpcService} type
* @param rpcImpl {@link RpcService} implementation
* @param bindUri URI to bind to
* @return {@link ResponderSession}
* @throws URISyntaxException if provided URI is invalid
*/
public ResponderSession createResponder(Class type, T rpcImpl, String bindUri)
throws URISyntaxException {
LOG.info("Creating responder type {} exposed on '{}'", type.getName(), bindUri);
final URI uri = new URI(bindUri);
return getMessageLibraryForTransport(uri.getScheme()).responder(bindUri,
new InboundHandler<>(type, invocationAdapter, rpcImpl), false);
}
@SuppressWarnings("unchecked")
public ResponderSession createMultiModelResponder(MultiModelBuilder builder, String bindUri)
throws URISyntaxException {
final ClassToInstanceMap services = builder.build();
LOG.info("Creating multi-model responder for services {} exposed on '{}'", services.keySet(), bindUri);
final URI uri = new URI(bindUri);
final Set> handlers = services.entrySet()
.stream()
.map(e -> new InboundHandler<>((Class) e.getKey(), invocationAdapter, e.getValue()))
.collect(Collectors.toSet());
return getMessageLibraryForTransport(uri.getScheme()).responder(bindUri,
new MultiModelRequestDispatcher(handlers), false);
}
/**
* Perform cleanup. Every proxy instance created by this {@link TransportFactory} is guaranteed to be closed once
* call to this method finished successfully.
*/
@Override
public void close() {
proxyMap.values().stream().forEach(ProxyContext::close);
proxyMap.clear();
super.close();
}
}