/* * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. 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.yangtools.concepts; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterators; import java.util.AbstractList; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; /** * Utility {@link ClassToInstanceMap} implementation for implementing {@link ExtensibleObject#getExtensions()} method * by objects which are themselves implementing the extension. * * @param Type of extensible object * @param Extension marker interface * @author Robert Varga */ @Beta public final class ObjectExtensions, E extends ObjectExtension> extends AbstractMap, E> implements ClassToInstanceMap { private final class EntrySet extends AbstractSet, E>> { @Override public Iterator, E>> iterator() { return Iterators.transform(extensions.iterator(), ext -> new SimpleImmutableEntry<>(ext, ext.cast(object))); } @Override public int size() { return extensions.size(); } } private static final class Values extends AbstractList { private final @NonNull E instance; private final int size; @SuppressWarnings("unchecked") Values(final @NonNull Object instance, final int size) { this.instance = (E) instance; this.size = size; } @Override public E get(final int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } return instance; } @Override public int size() { return size; } } public static final class Factory, E extends ObjectExtension> { private final @NonNull ImmutableSet> extensions; Factory(final ImmutableSet> extensions) { this.extensions = requireNonNull(extensions); } public @NonNull ClassToInstanceMap newInstance(final T object) { return new ObjectExtensions<>(extensions, object); } } private final @NonNull ImmutableSet> extensions; private final @NonNull Object object; ObjectExtensions(final ImmutableSet> extensions, final Object object) { this.extensions = requireNonNull(extensions); this.object = requireNonNull(object); } @SafeVarargs public static , E extends ObjectExtension> @NonNull Factory factory(final Class objClass, final Class... extensions) { final ImmutableSet> set = ImmutableSet.copyOf(extensions); for (Class extension : set) { checkArgument(extension.isAssignableFrom(objClass), "%s is not a valid extension %s", objClass, extension); } return new Factory<>(set); } @Override public int size() { return extensions.size(); } @Override public boolean isEmpty() { return extensions.isEmpty(); } @Override public boolean containsKey(final Object key) { return extensions.contains(key); } @Override public boolean containsValue(final Object value) { return object.equals(value); } @Override public E get(final Object key) { return containsKey(key) ? ((Class) key).cast(object) : null; } @Override public E put(final Class key, final E value) { throw new UnsupportedOperationException(); } @Override public E remove(final Object key) { throw new UnsupportedOperationException(); } @Override @SuppressWarnings("checkstyle:parameterName") public void putAll(final Map, ? extends E> m) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public Set> keySet() { return extensions; } @Override public Collection values() { return new Values<>(object, extensions.size()); } @Override public Set, E>> entrySet() { return new EntrySet(); } @Override public T getInstance(final Class type) { return extensions.contains(requireNonNull(type)) ? type.cast(object) : null; } @Override public T putInstance(final Class type, final T value) { throw new UnsupportedOperationException(); } }