2 * Copyright (c) 2018 ZTE Corp. 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.mdsal.dom.broker;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.ImmutableMap.Builder;
17 import com.google.common.collect.ListMultimap;
18 import com.google.common.collect.Maps;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.EventListener;
22 import java.util.HashMap;
23 import java.util.List;
25 import java.util.Map.Entry;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
30 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
33 * Abstract routing table definition for Action and RPC.
34 * @param <I> instance type of RPC or Acton
35 * @param <D> identifier type of RPC or Acton
36 * @param <M> implementation type of RPC or Acton
37 * @param <L> listener type of RPC or Acton
38 * @param <E> routing entry type of RPC or Acton
41 abstract class AbstractDOMRoutingTable<I, D, M, L extends EventListener,
42 E extends AbstractDOMRoutingTableEntry<D, M, L>> {
43 private final Map<SchemaPath, E> operations;
44 private final SchemaContext schemaContext;
46 AbstractDOMRoutingTable(final Map<SchemaPath, E> operations,
47 final SchemaContext schemaContext) {
48 this.operations = requireNonNull(operations);
49 this.schemaContext = schemaContext;
52 AbstractDOMRoutingTable<I, D, M, L, E> setSchemaContext(final SchemaContext context) {
53 final Builder<SchemaPath, E> b = ImmutableMap.builder();
55 for (Entry<SchemaPath, E> e : operations.entrySet()) {
56 final E entry = createOperationEntry(context, e.getKey(),
57 e.getValue().getImplementations());
59 b.put(e.getKey(), entry);
63 return newInstance(b.build(), context);
66 AbstractDOMRoutingTable<I, D, M, L, E> add(final M implementation, final Set<I> oprsToAdd) {
67 if (oprsToAdd.isEmpty()) {
71 // First decompose the identifiers to a multimap
72 final ListMultimap<SchemaPath, D> toAdd = decomposeIdentifiers(oprsToAdd);
74 // Now iterate over existing entries, modifying them as appropriate...
75 final Builder<SchemaPath, E> mb = ImmutableMap.builder();
76 for (Entry<SchemaPath, E> re : this.operations.entrySet()) {
77 List<D> newOperations = new ArrayList<>(toAdd.removeAll(re.getKey()));
78 if (!newOperations.isEmpty()) {
79 final E ne = (E) re.getValue().add(implementation, newOperations);
80 mb.put(re.getKey(), ne);
86 // Finally add whatever is left in the decomposed multimap
87 for (Entry<SchemaPath, Collection<D>> e : toAdd.asMap().entrySet()) {
88 final Builder<D, List<M>> vb = ImmutableMap.builder();
89 final List<M> v = ImmutableList.of(implementation);
90 for (D i : e.getValue()) {
94 final E entry = createOperationEntry(schemaContext, e.getKey(),
97 mb.put(e.getKey(), entry);
101 return newInstance(mb.build(), schemaContext);
104 AbstractDOMRoutingTable<I, D, M, L, E> remove(final M implementation, final Set<I> instances) {
105 if (instances.isEmpty()) {
109 // First decompose the identifiers to a multimap
110 final ListMultimap<SchemaPath, D> toRemove = decomposeIdentifiers(instances);
112 // Now iterate over existing entries, modifying them as appropriate...
113 final Builder<SchemaPath, E> b = ImmutableMap.builder();
114 for (Entry<SchemaPath, E> e : this.operations.entrySet()) {
115 final List<D> removed = new ArrayList<>(toRemove.removeAll(e.getKey()));
116 if (!removed.isEmpty()) {
117 final E ne = (E) e.getValue().remove(implementation, removed);
119 b.put(e.getKey(), ne);
126 // All done, whatever is in toRemove, was not there in the first place
127 return newInstance(b.build(), schemaContext);
131 Map<SchemaPath, Set<D>> getOperations() {
132 return Maps.transformValues(operations, AbstractDOMRoutingTableEntry::registeredIdentifiers);
135 Map<SchemaPath, Set<D>> getOperations(final L listener) {
136 final Map<SchemaPath, Set<D>> ret = new HashMap<>(operations.size());
137 for (Entry<SchemaPath, E> e : operations.entrySet()) {
138 final Set<D> ids = e.getValue().registeredIdentifiers(listener);
139 if (!ids.isEmpty()) {
140 ret.put(e.getKey(), ids);
147 @Nullable AbstractDOMRoutingTableEntry<D, M, L> getEntry(final @NonNull SchemaPath type) {
148 return operations.get(type);
151 protected abstract AbstractDOMRoutingTable<I, D, M, L, E> newInstance(Map<SchemaPath, E> operations,
152 SchemaContext schemaContext);
154 abstract ListMultimap<SchemaPath, D> decomposeIdentifiers(Set<I> instances);
156 abstract E createOperationEntry(SchemaContext context, SchemaPath key, Map<D, List<M>> implementations);