2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.md.sal.dom.broker.impl;
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.collect.ImmutableSet;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.util.Collection;
17 import java.util.Collections;
20 import java.util.WeakHashMap;
21 import java.util.stream.Collectors;
22 import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
23 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
24 import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
25 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
26 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
27 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
28 import org.opendaylight.controller.md.sal.dom.api.DOMRpcProviderService;
29 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
30 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
31 import org.opendaylight.controller.md.sal.dom.api.DefaultDOMRpcException;
32 import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMRpcImplementationRegistration;
33 import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
34 import org.opendaylight.mdsal.common.api.MappingCheckedFuture;
35 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
36 import org.opendaylight.yangtools.concepts.ListenerRegistration;
37 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
38 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
41 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
43 public final class DOMRpcRouter implements AutoCloseable, DOMRpcService, DOMRpcProviderService, SchemaContextListener {
44 private static final ExceptionMapper<org.opendaylight.mdsal.dom.api.DOMRpcException> MDSAL_DOM_RPC_EX_MAPPER =
45 new ExceptionMapper<org.opendaylight.mdsal.dom.api.DOMRpcException>(
46 "rpc", org.opendaylight.mdsal.dom.api.DOMRpcException.class) {
48 protected org.opendaylight.mdsal.dom.api.DOMRpcException newWithCause(String message, Throwable cause) {
49 return cause instanceof org.opendaylight.mdsal.dom.api.DOMRpcException
50 ? (org.opendaylight.mdsal.dom.api.DOMRpcException)cause
51 : new org.opendaylight.mdsal.dom.api.DefaultDOMRpcException("RPC failed", cause);
55 private static final ExceptionMapper<DOMRpcException> LEGACY_DOM_RPC_EX_MAPPER =
56 new ExceptionMapper<DOMRpcException>("rpc", DOMRpcException.class) {
58 protected DOMRpcException newWithCause(String message, Throwable cause) {
59 return cause instanceof DOMRpcException ? (DOMRpcException)cause
60 : cause instanceof org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException
61 ? new DOMRpcImplementationNotAvailableException(cause.getMessage(), cause.getCause())
62 : new DefaultDOMRpcException("RPC failed", cause);
66 // This mapping is used to translate mdsal DOMRpcImplementations to their corresponding legacy
67 // DOMRpcImplementations registered thru this interface when invoking a DOMRpcAvailabilityListener.
68 private final Map<org.opendaylight.mdsal.dom.api.DOMRpcImplementation, DOMRpcImplementation> implMapping =
69 Collections.synchronizedMap(new WeakHashMap<>());
71 private final org.opendaylight.mdsal.dom.api.DOMRpcService delegateRpcService;
72 private final org.opendaylight.mdsal.dom.api.DOMRpcProviderService delegateRpcProviderService;
75 public DOMRpcRouter() {
76 org.opendaylight.mdsal.dom.broker.DOMRpcRouter delegate = new org.opendaylight.mdsal.dom.broker.DOMRpcRouter();
77 this.delegateRpcService = delegate;
78 this.delegateRpcProviderService = delegate;
81 public DOMRpcRouter(final org.opendaylight.mdsal.dom.api.DOMRpcService delegateRpcService,
82 final org.opendaylight.mdsal.dom.api.DOMRpcProviderService delegateRpcProviderService) {
83 this.delegateRpcService = delegateRpcService;
84 this.delegateRpcProviderService = delegateRpcProviderService;
88 public <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(
89 final T implementation, final DOMRpcIdentifier... rpcs) {
90 return registerRpcImplementation(implementation, ImmutableSet.copyOf(rpcs));
93 @SuppressWarnings({ "unchecked", "rawtypes" })
95 public synchronized <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(
96 final T implementation, final Set<DOMRpcIdentifier> rpcs) {
97 org.opendaylight.mdsal.dom.api.DOMRpcImplementation delegateImpl =
98 new org.opendaylight.mdsal.dom.api.DOMRpcImplementation() {
100 public CheckedFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult,
101 org.opendaylight.mdsal.dom.api.DOMRpcException> invokeRpc(
102 org.opendaylight.mdsal.dom.api.DOMRpcIdentifier rpc, NormalizedNode<?, ?> input) {
103 final ListenableFuture future = implementation.invokeRpc(convert(rpc), input);
104 return MappingCheckedFuture.create(future, MDSAL_DOM_RPC_EX_MAPPER);
108 public long invocationCost() {
109 return implementation.invocationCost();
113 implMapping.put(delegateImpl, implementation);
115 final org.opendaylight.mdsal.dom.api.DOMRpcImplementationRegistration
116 <org.opendaylight.mdsal.dom.api.DOMRpcImplementation> reg = delegateRpcProviderService
117 .registerRpcImplementation(delegateImpl,
118 rpcs.stream().map(DOMRpcRouter::convert).collect(Collectors.toSet()));
120 return new AbstractDOMRpcImplementationRegistration<T>(implementation) {
122 protected void removeRegistration() {
124 implMapping.remove(delegateImpl);
129 private static org.opendaylight.mdsal.dom.api.DOMRpcIdentifier convert(DOMRpcIdentifier from) {
130 return org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(from.getType(), from.getContextReference());
133 private static DOMRpcIdentifier convert(org.opendaylight.mdsal.dom.api.DOMRpcIdentifier from) {
134 return DOMRpcIdentifier.create(from.getType(), from.getContextReference());
137 private static ListenableFuture<DOMRpcResult> convert(org.opendaylight.mdsal.dom.api.DOMRpcResult from) {
138 return from == null ? Futures.immediateFuture(null)
139 : from instanceof DOMRpcResult ? Futures.immediateFuture((DOMRpcResult)from)
140 : Futures.immediateFuture(new DefaultDOMRpcResult(from.getResult(), from.getErrors()));
143 private static Collection<DOMRpcIdentifier> convert(
144 Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> from) {
145 return from.stream().map(DOMRpcRouter::convert).collect(Collectors.toList());
149 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
150 final NormalizedNode<?, ?> input) {
151 final ListenableFuture<DOMRpcResult> future = Futures.transformAsync(delegateRpcService.invokeRpc(type, input),
152 DOMRpcRouter::convert, MoreExecutors.directExecutor());
153 return MappingCheckedFuture.create(future, LEGACY_DOM_RPC_EX_MAPPER);
157 public synchronized <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(
159 final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener> reg =
160 delegateRpcService.registerRpcListener(new org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener() {
162 public void onRpcAvailable(Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> rpcs) {
163 listener.onRpcAvailable(convert(rpcs));
167 public void onRpcUnavailable(Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> rpcs) {
168 listener.onRpcUnavailable(convert(rpcs));
172 public boolean acceptsImplementation(final org.opendaylight.mdsal.dom.api.DOMRpcImplementation impl) {
173 // If the DOMRpcImplementation wasn't registered thru this interface then the mapping won't be
174 // present - in this we can't call the listener so just assume acceptance which is the default
175 // behavior. This should be fine since a legacy listener would not be aware of implementation types
176 // registered via the new mdsal API.
177 final DOMRpcImplementation legacyImpl = implMapping.get(impl);
178 return legacyImpl != null ? listener.acceptsImplementation(legacyImpl) : true;
182 return new AbstractListenerRegistration<T>(listener) {
184 protected void removeRegistration() {
191 public void close() {
196 public void onGlobalContextUpdated(final SchemaContext context) {
197 if (delegateRpcService instanceof SchemaContextListener) {
198 ((SchemaContextListener)delegateRpcService).onGlobalContextUpdated(context);