1 package org.onap.sdc.dcae.catalog.commons;
4 import java.util.LinkedList;
6 import java.util.Collections;
8 import java.util.stream.Collectors;
10 import java.lang.annotation.ElementType;
11 import java.lang.annotation.Retention;
12 import java.lang.annotation.RetentionPolicy;
13 import java.lang.annotation.Target;
15 import java.lang.reflect.Type;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Array;
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.ParameterizedType;
20 import java.lang.reflect.InvocationHandler;
21 import java.lang.reflect.InvocationTargetException;
23 import java.lang.invoke.MethodHandles;
25 import com.google.common.reflect.Invokable;
26 import org.onap.sdc.dcae.catalog.commons.Proxy;
27 import org.onap.sdc.dcae.catalog.commons.ProxyBuilder;
28 import com.google.common.reflect.AbstractInvocationHandler;
30 import org.apache.commons.beanutils.ConvertUtils;
32 import org.json.JSONObject;
33 import org.json.JSONArray;
35 public class Proxy extends AbstractInvocationHandler {
37 @Retention(RetentionPolicy.RUNTIME)
38 @Target(ElementType.METHOD)
40 public static @interface DataMap {
42 public String map() default "";
44 public boolean proxy() default false;
46 public Class elementType() default Void.class;
50 public static final Constructor<MethodHandles.Lookup> lookupHandleConstructor;
54 lookupHandleConstructor =
55 MethodHandles.Lookup.class.getDeclaredConstructor(Class.class,
58 if (!lookupHandleConstructor.isAccessible()) {
59 lookupHandleConstructor.setAccessible(true);
63 throw new RuntimeException(x);
68 private JSONObject data;
69 private ProxyBuilder builder;
71 protected Proxy(JSONObject theData, ProxyBuilder theBuilder) {
73 this.builder = theBuilder;
76 public JSONObject data() {
80 public ProxyBuilder getBuilder() {
84 protected Object handleInvocation(
85 Object theProxy,Method theMethod,Object[] theArgs)
87 if (theMethod.isDefault()) {
88 final Class<?> declaringClass = theMethod.getDeclaringClass();
90 return lookupHandleConstructor
91 .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
92 .unreflectSpecial(theMethod, declaringClass)
94 .invokeWithArguments(theArgs);
97 String key = theMethod.getName();
99 Proxy.DataMap dataMap = (Proxy.DataMap)theMethod.getAnnotation(Proxy.DataMap.class);
100 if (dataMap != null) {
101 String dataKey = dataMap.map();
102 if (dataKey != null && !"".equals(dataKey))
106 //this is ugly, can this be done through an extension mechanism such as plugging in functions?
107 if ( builder.hasExtension(key) )
108 return this.builder.extension(key).apply(this, theArgs);
110 //we give priority to the context (because of the 'catalog' property issue in catalog service) but
111 //how natural is this?
112 Object val = this.builder.context(key);
114 val = this.data.opt(key);
119 //as we create proxies here we should store them back in the 'data' so that we do not do it again
120 //can we always 'recognize' them?
121 if (val instanceof String &&
122 String.class != theMethod.getReturnType()) {
123 //??This will yield a POJO ..
124 return ConvertUtils.convert((String)val, theMethod.getReturnType());
126 else if (val instanceof JSONObject) {
127 if (dataMap != null && dataMap.proxy()) {
128 return builder.build((JSONObject)val, theMethod.getReturnType());
131 else if (val instanceof JSONArray&& dataMap != null &&
133 List.class.isAssignableFrom(theMethod.getReturnType())) {
135 List res = (List) theMethod.getReturnType().newInstance();
136 for (int i = 0; i < ((JSONArray) val).length(); i++) {
137 res.add(builder.build(((JSONArray) val).getJSONObject(i), dataMap.elementType()));