2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.yangtools.concepts;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.ClassToInstanceMap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Iterators;
17 import java.util.AbstractList;
18 import java.util.AbstractMap;
19 import java.util.AbstractSet;
20 import java.util.Collection;
21 import java.util.Iterator;
24 import org.eclipse.jdt.annotation.NonNull;
27 * Utility {@link ClassToInstanceMap} implementation for implementing {@link ExtensibleObject#getExtensions()} method
28 * by objects which are themselves implementing the extension.
30 * @param <O> Type of extensible object
31 * @param <E> Extension marker interface
32 * @author Robert Varga
35 public final class ObjectExtensions<O extends ExtensibleObject<O, E>, E extends ObjectExtension<O, E>>
36 extends AbstractMap<Class<? extends E>, E> implements ClassToInstanceMap<E> {
37 private final class EntrySet extends AbstractSet<Entry<Class<? extends E>, E>> {
39 public Iterator<Entry<Class<? extends E>, E>> iterator() {
40 return Iterators.transform(extensions.iterator(), ext -> new SimpleImmutableEntry<>(ext, ext.cast(object)));
45 return extensions.size();
49 private static final class Values<E> extends AbstractList<E> {
50 private final @NonNull E instance;
51 private final int size;
53 @SuppressWarnings("unchecked")
54 Values(final @NonNull Object instance, final int size) {
55 this.instance = (E) instance;
60 public E get(final int index) {
61 if (index < 0 || index >= size) {
62 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
73 public static final class Factory<T, O extends ExtensibleObject<O, E>, E extends ObjectExtension<O, E>> {
74 private final @NonNull ImmutableSet<Class<? extends E>> extensions;
76 Factory(final ImmutableSet<Class<? extends E>> extensions) {
77 this.extensions = requireNonNull(extensions);
80 public @NonNull ClassToInstanceMap<E> newInstance(final T object) {
81 return new ObjectExtensions<>(extensions, object);
85 private final @NonNull ImmutableSet<Class<? extends E>> extensions;
86 private final @NonNull Object object;
88 ObjectExtensions(final ImmutableSet<Class<? extends E>> extensions, final Object object) {
89 this.extensions = requireNonNull(extensions);
90 this.object = requireNonNull(object);
94 public static <T, O extends ExtensibleObject<O, E>, E extends ObjectExtension<O, E>> @NonNull Factory<T, O, E>
95 factory(final Class<T> objClass, final Class<? extends E>... extensions) {
96 final ImmutableSet<Class<? extends E>> set = ImmutableSet.copyOf(extensions);
97 for (Class<? extends E> extension : set) {
98 checkArgument(extension.isAssignableFrom(objClass), "%s is not a valid extension %s", objClass, extension);
100 return new Factory<>(set);
105 return extensions.size();
109 public boolean isEmpty() {
110 return extensions.isEmpty();
114 public boolean containsKey(final Object key) {
115 return extensions.contains(key);
119 public boolean containsValue(final Object value) {
120 return object.equals(value);
124 public E get(final Object key) {
125 return containsKey(key) ? ((Class<? extends E>) key).cast(object) : null;
129 public E put(final Class<? extends E> key, final E value) {
130 throw new UnsupportedOperationException();
134 public E remove(final Object key) {
135 throw new UnsupportedOperationException();
139 @SuppressWarnings("checkstyle:parameterName")
140 public void putAll(final Map<? extends Class<? extends E>, ? extends E> m) {
141 throw new UnsupportedOperationException();
145 public void clear() {
146 throw new UnsupportedOperationException();
150 public Set<Class<? extends E>> keySet() {
155 public Collection<E> values() {
156 return new Values<>(object, extensions.size());
160 public Set<Entry<Class<? extends E>, E>> entrySet() {
161 return new EntrySet();
165 public <T extends E> T getInstance(final Class<T> type) {
166 return extensions.contains(requireNonNull(type)) ? type.cast(object) : null;
170 public <T extends E> T putInstance(final Class<T> type, final T value) {
171 throw new UnsupportedOperationException();