summaryrefslogtreecommitdiffstats
path: root/dcaedt_catalog/commons/src/main/java/org/onap/sdc/dcae/catalog/commons/Proxy.pojo
blob: b3b5cb903f802205c163e3ca67f1b5e2ed283265 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package org.onap.sdc.dcae.catalog.commons;

import java.util.List;
import java.util.Map;
import java.util.Collections;

import java.util.stream.Collectors;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import java.lang.reflect.Type;
import java.lang.reflect.Method;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;

import java.lang.invoke.MethodHandles;

import com.google.common.reflect.Invokable;
import com.google.common.reflect.AbstractInvocationHandler;

import org.apache.commons.beanutils.ConvertUtils;


/**
 */
public class Proxy 
									extends AbstractInvocationHandler {

	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.METHOD)

	public static @interface DataMap {

		public String map() default "";

		public boolean proxy() default false;
		
		public Class elementType() default Void.class;
	}
	

	public static Constructor<MethodHandles.Lookup> lookupHandleConstructor;

	static {
		try {
			lookupHandleConstructor =
					MethodHandles.Lookup.class.getDeclaredConstructor(Class.class,
																														int.class);

			if (!lookupHandleConstructor.isAccessible()) {
   			lookupHandleConstructor.setAccessible(true);
			}
		}
		catch (Exception x) {
			throw new RuntimeException(x);
		}	
	}


	private Map						data;
	private ProxyBuilder	builder;

	protected Proxy(Map theData, ProxyBuilder theBuilder) {
		this.data = theData;
		this.builder = theBuilder;
	}

	public Map data() {
		return this.data;
	}

	public ProxyBuilder getBuilder() {
		return this.builder;
	}

	protected Object handleInvocation(
											Object theProxy,Method theMethod,Object[] theArgs)
																												throws Throwable {
		if (theMethod.isDefault()) {
				final Class<?> declaringClass = theMethod.getDeclaringClass();
				/*
				return MethodHandles.lookup()
								.in(declaringClass)
								.unreflectSpecial(theMethod, declaringClass)
								.bindTo(theProxy)
								.invokeWithArguments(theArgs);
				*/
			return lookupHandleConstructor
							.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
							.unreflectSpecial(theMethod, declaringClass)
							.bindTo(theProxy)
							.invokeWithArguments(theArgs);
		}

		String key = theMethod.getName();

		Proxy.DataMap dataMap = (Proxy.DataMap)theMethod.getAnnotation(Proxy.DataMap.class);	
		if (dataMap != null) {
			String dataKey = dataMap.map();
			if (dataKey != null && !"".equals(dataKey))
				key = dataKey;
		}

		//this is ugly, can this be done through an extension mechanism such as plugging in functions?
		if ( builder.hasExtension(key) )
			return this.builder.extension(key).apply(this, theArgs);
		
		Object val = this.data.getOrDefault(key, this.builder.context(key));

System.out.println("!! " + key + " : " + val);

//as we create proxies here we should store them back in the 'data' so that we do not do it again
//can we always 'recognize' them?
		if (val instanceof String &&
				String.class != theMethod.getReturnType()) {
			return ConvertUtils.convert((String)val, theMethod.getReturnType());
		}
		else if (val instanceof Map) {
			if (dataMap != null && dataMap.proxy()) {
				return builder.build((Map)val, theMethod.getReturnType());
			}
		}
		else if (val instanceof List) {
			if (dataMap != null && dataMap.proxy()) {
       	return ((List)val)
								.stream()
									.map(e -> this.builder.build((Map)e, dataMap.elementType()))
										.collect(Collectors.toList());
			}
		}
/*
		else if (val.getClass().isArray()) {
			if (dataMap != null && dataMap.proxy()) {
			}
		}
*/	
		return val;
	}
}