From 7aba6e53e4b142895dcd57f26eb87e8ba133f6d0 Mon Sep 17 00:00:00 2001 From: Jakub Toth Date: Wed, 14 Jun 2017 12:06:45 +0200 Subject: [PATCH] Binding v2 runtime - adapters - extractors Change-Id: I0ee755ae25ad772b844ce70c3afdb76ba25d3b15 Signed-off-by: Jakub Toth (cherry picked from commit f84f1466990a488a1ec17a6239a58fbdd86da832) --- .../javav2/api/annotation/RoutingContext.java | 27 ++++ .../extractor/ContextReferenceExtractor.java | 119 ++++++++++++++++++ .../DirectGetterRouteContextExtractor.java | 45 +++++++ .../GetValueRouteContextExtractor.java | 54 ++++++++ 4 files changed, 245 insertions(+) create mode 100644 binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/annotation/RoutingContext.java create mode 100644 binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/ContextReferenceExtractor.java create mode 100644 binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/DirectGetterRouteContextExtractor.java create mode 100644 binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/GetValueRouteContextExtractor.java diff --git a/binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/annotation/RoutingContext.java b/binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/annotation/RoutingContext.java new file mode 100644 index 0000000000..a6f9a51163 --- /dev/null +++ b/binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/annotation/RoutingContext.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 Pantheon Technologies 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.mdsal.binding.javav2.api.annotation; + +import com.google.common.annotations.Beta; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.opendaylight.mdsal.binding.javav2.spec.base.BaseIdentity; + +@Beta +@Inherited +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface RoutingContext { + + Class value(); +} diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/ContextReferenceExtractor.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/ContextReferenceExtractor.java new file mode 100644 index 0000000000..20e2d788f0 --- /dev/null +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/ContextReferenceExtractor.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017 Pantheon Technologies 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.mdsal.binding.javav2.dom.adapter.extractor; + +import com.google.common.annotations.Beta; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import java.lang.reflect.Method; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.mdsal.binding.javav2.api.annotation.RoutingContext; +import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier; +import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tree node reference extractor. + */ +@Beta +public abstract class ContextReferenceExtractor { + + private static final Logger LOG = LoggerFactory.getLogger(ContextReferenceExtractor.class); + private static final String GET_VALUE_NAME = "getValue"; + + private static final ContextReferenceExtractor NULL_EXTRACTOR = new ContextReferenceExtractor() { + + @Nullable + @Override + public InstanceIdentifier extract(final TreeNode obj) { + return null; + } + }; + + private static final LoadingCache, ContextReferenceExtractor> EXTRACTORS = + CacheBuilder.newBuilder().weakKeys().build(new CacheLoader, ContextReferenceExtractor>() { + + @Nonnull + @Override + public ContextReferenceExtractor load(@Nonnull final Class key) throws Exception { + return create(key); + } + + private ContextReferenceExtractor create(final Class key) { + final Method contextGetter = getContextGetter(key); + if (contextGetter == null) { + return NULL_EXTRACTOR; + } + final Class returnType = contextGetter.getReturnType(); + try { + if (InstanceIdentifier.class.isAssignableFrom(returnType)) { + return DirectGetterRouteContextExtractor.create(contextGetter); + } + final Method getValueMethod = findGetValueMethod(returnType); + if (getValueMethod != null) { + return GetValueRouteContextExtractor.create(contextGetter, getValueMethod); + } else { + LOG.warn("Class {} can not be used to determine context, falling back to NULL_EXTRACTOR.", + returnType); + } + } catch (final IllegalAccessException e) { + LOG.warn("Class {} does not conform to Binding Specification. Falling back to NULL_EXTRACTOR", + e); + } + return NULL_EXTRACTOR; + } + + private Method getContextGetter(final Class key) { + for (final Method method : key.getMethods()) { + if (method.getAnnotation(RoutingContext.class) != null) { + return method; + } + } + return null; + } + }); + + /** + * Extract context-reference (Instance Identifier) from Binding TreeNode. + * + * @param obj + * - TreeNode from which context reference should be extracted. + * + * @return Instance Identifier representing context reference or null, if tree node does not contain + * context reference. + */ + @Nullable + public abstract InstanceIdentifier extract(TreeNode obj); + + /** + * Method for return specific extractor of input object. + * + * @param obj + * - object for get specific extractor + * @return specific extractor + */ + public static ContextReferenceExtractor from(final Class obj) { + return EXTRACTORS.getUnchecked(obj); + } + + private static Method findGetValueMethod(final Class type) { + try { + final Method method = type.getMethod(GET_VALUE_NAME); + if (InstanceIdentifier.class.equals(method.getReturnType())) { + return method; + } + } catch (final NoSuchMethodException e) { + LOG.warn("Value class {} does not comform to Binding Specification.", type, e); + } + return null; + } +} + diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/DirectGetterRouteContextExtractor.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/DirectGetterRouteContextExtractor.java new file mode 100644 index 0000000000..9ea627cbde --- /dev/null +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/DirectGetterRouteContextExtractor.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017 Pantheon Technologies 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.mdsal.binding.javav2.dom.adapter.extractor; + +import com.google.common.annotations.Beta; +import com.google.common.base.Throwables; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier; +import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode; + +@Beta +final class DirectGetterRouteContextExtractor extends ContextReferenceExtractor { + + private static final Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup(); + + private final MethodHandle handle; + + private DirectGetterRouteContextExtractor(final MethodHandle rawHandle) { + handle = rawHandle.asType(MethodType.methodType(InstanceIdentifier.class, TreeNode.class)); + } + + static ContextReferenceExtractor create(final Method getterMethod) throws IllegalAccessException { + final MethodHandle getterHandle = PUBLIC_LOOKUP.unreflect(getterMethod); + return new DirectGetterRouteContextExtractor(getterHandle); + } + + @SuppressWarnings("checkstyle:IllegalCatch") + @Override + public InstanceIdentifier extract(final TreeNode obj) { + try { + return (InstanceIdentifier) handle.invokeExact(obj); + } catch (final Throwable e) { + throw Throwables.propagate(e); + } + } +} \ No newline at end of file diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/GetValueRouteContextExtractor.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/GetValueRouteContextExtractor.java new file mode 100644 index 0000000000..114a51dd4e --- /dev/null +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/extractor/GetValueRouteContextExtractor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Pantheon Technologies 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.mdsal.binding.javav2.dom.adapter.extractor; + +import com.google.common.annotations.Beta; +import com.google.common.base.Throwables; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier; +import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode; + +@Beta +final class GetValueRouteContextExtractor extends ContextReferenceExtractor { + + private static final Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup(); + + private final MethodHandle contextHandle; + private final MethodHandle valueHandle; + + private GetValueRouteContextExtractor(final MethodHandle rawContextHandle, final MethodHandle rawValueHandle) { + contextHandle = rawContextHandle.asType(MethodType.methodType(Object.class, TreeNode.class)); + valueHandle = rawValueHandle.asType(MethodType.methodType(InstanceIdentifier.class, Object.class)); + } + + static ContextReferenceExtractor create(final Method contextGetter, final Method getValueMethod) + throws IllegalAccessException { + final MethodHandle rawContextHandle = PUBLIC_LOOKUP.unreflect(contextGetter); + final MethodHandle rawValueHandle = PUBLIC_LOOKUP.unreflect(getValueMethod); + return new GetValueRouteContextExtractor(rawContextHandle, rawValueHandle); + } + + @SuppressWarnings("checkstyle:IllegalCatch") + @Override + public InstanceIdentifier extract(final TreeNode obj) { + try { + final Object ctx = contextHandle.invokeExact(obj); + if (ctx != null) { + return (InstanceIdentifier) valueHandle.invokeExact(ctx); + } + return null; + } catch (final Throwable e) { + throw Throwables.propagate(e); + } + } +} + -- 2.36.6