2 * Copyright (c) 2013 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.protocol.concepts;
10 import java.util.List;
11 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.concurrent.ConcurrentMap;
14 import javax.annotation.concurrent.GuardedBy;
15 import javax.annotation.concurrent.ThreadSafe;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
20 import com.google.common.collect.ArrayListMultimap;
21 import com.google.common.collect.ListMultimap;
24 * A registry which allows multiple values for a particular key. One of those
25 * is considered the best and returned as the representative.
27 * When selecting the candidate, we evaluate the order of insertion, picking the
28 * value inserted first, but then we look at all the other candidates and if there
29 * is one which is a subclass of the first one, we select that one.
32 * @param <V> value type
35 public final class MultiRegistry<K, V> {
36 private static final Logger LOG = LoggerFactory.getLogger(MultiRegistry.class);
37 private final ConcurrentMap<K, V> current = new ConcurrentHashMap<>();
40 private final ListMultimap<K, V> candidates = ArrayListMultimap.create();
43 private void updateCurrent(final K key) {
44 final List<V> values = candidates.get(key);
46 // Simple case: no candidates
47 if (values.isEmpty()) {
52 V best = values.get(0);
54 final Class<?> vc = v.getClass();
55 final Class<?> bc = best.getClass();
56 if (bc.isAssignableFrom(vc)) {
57 LOG.debug("{} is superclass of {}, preferring the latter", bc, vc);
59 } else if (vc.isAssignableFrom(bc)) {
60 LOG.debug("{} is subclass of {}, preferring the former", bc, vc);
62 LOG.debug("{} and {} are not related, keeping the former", bc, vc);
66 LOG.debug("New best value {}", best);
67 current.put(key, best);
70 public synchronized AbstractRegistration register(final K key, final V value) {
71 candidates.put(key, value);
74 final Object lock = this;
75 return new AbstractRegistration() {
77 protected void removeRegistration() {
79 candidates.remove(key, value);
86 public V get(final K key) {
87 return this.current.get(key);