2 * Copyright (c) 2014 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.yangtools.yang.binding.util;
10 import com.google.common.base.Preconditions;
11 import com.google.common.cache.CacheBuilder;
12 import com.google.common.cache.CacheLoader;
13 import com.google.common.cache.LoadingCache;
14 import java.lang.invoke.MethodHandle;
15 import java.lang.invoke.MethodHandles;
16 import java.lang.invoke.MethodHandles.Lookup;
17 import java.lang.invoke.MethodType;
18 import java.lang.reflect.Field;
19 import java.util.Collections;
21 import org.opendaylight.yangtools.yang.binding.Augmentation;
22 import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
23 import org.opendaylight.yangtools.yang.binding.BindingMapping;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 abstract class AugmentationFieldGetter {
29 private static final Logger LOG = LoggerFactory.getLogger(AugmentationFieldGetter.class);
31 private static final AugmentationFieldGetter DUMMY = new AugmentationFieldGetter() {
33 protected Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
34 return Collections.emptyMap();
38 private static final AugmentationFieldGetter AUGMENTATION_HOLDER_GETTER = new AugmentationFieldGetter() {
41 @SuppressWarnings({"unchecked", "rawtypes"})
42 protected Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
43 return (Map) ((AugmentationHolder<?>) input).augmentations();
47 private static final LoadingCache<Class<?>, AugmentationFieldGetter> AUGMENTATION_GETTERS = CacheBuilder.newBuilder().weakKeys().build(
48 new AugmentationGetterLoader());
52 * Retrieves augmentations from supplied object
54 * @param input Input Data object, from which augmentations should be extracted
55 * @return Map of Augmentation class to augmentation
57 protected abstract Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input);
59 public static AugmentationFieldGetter getGetter(final Class<? extends Object> clz) {
60 if(AugmentationHolder.class.isAssignableFrom(clz)) {
61 return AUGMENTATION_HOLDER_GETTER;
63 return AUGMENTATION_GETTERS.getUnchecked(clz);
66 private static final class AugmentationGetterLoader extends CacheLoader<Class<?>, AugmentationFieldGetter> {
67 private static final MethodType GETTER_TYPE = MethodType.methodType(Map.class, Object.class);
68 private static final Lookup LOOKUP = MethodHandles.lookup();
71 public AugmentationFieldGetter load(final Class<?> key) throws IllegalAccessException {
74 field = key.getDeclaredField(BindingMapping.AUGMENTATION_FIELD);
75 field.setAccessible(true);
76 } catch (NoSuchFieldException | SecurityException e) {
77 LOG.warn("Failed to acquire augmentation field {}, ignoring augmentations in class {}",
78 BindingMapping.AUGMENTATION_FIELD, key, e);
81 if (!Map.class.isAssignableFrom(field.getType())) {
82 LOG.warn("Class {} field {} is not a Map, ignoring augmentations", key,
83 BindingMapping.AUGMENTATION_FIELD);
87 return new ReflectionAugmentationFieldGetter(LOOKUP.unreflectGetter(field).asType(GETTER_TYPE));
91 private static final class ReflectionAugmentationFieldGetter extends AugmentationFieldGetter {
92 private final MethodHandle fieldGetter;
94 ReflectionAugmentationFieldGetter(final MethodHandle mh) {
95 this.fieldGetter = Preconditions.checkNotNull(mh);
99 protected Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Object input) {
101 return (Map<Class<? extends Augmentation<?>>, Augmentation<?>>) fieldGetter.invokeExact(input);
102 } catch (Throwable e) {
103 throw new IllegalStateException("Failed to access augmentation field on " + input, e);