1
1
package com .microsoft .azure .functions .worker .binding ;
2
2
3
- import com .microsoft .azure .functions .ExecutionContext ;
4
- import com .microsoft .azure .functions .RetryContext ;
5
- import com .microsoft .azure .functions .TraceContext ;
3
+ import com .microsoft .azure .functions .*;
4
+ import com .microsoft .azure .functions .internal .spi .middleware .MiddlewareContext ;
5
+ import com .microsoft .azure .functions .rpc .messages .ParameterBinding ;
6
+ import com .microsoft .azure .functions .rpc .messages .TypedData ;
6
7
import com .microsoft .azure .functions .worker .WorkerLogManager ;
7
8
import com .microsoft .azure .functions .worker .broker .MethodBindInfo ;
8
- import java . util . logging . Logger ;
9
+ import com . microsoft . azure . functions . worker . broker . ParamBindInfo ;
9
10
10
- public final class ExecutionContextDataSource extends DataSource <ExecutionContext > implements ExecutionContext {
11
+ import java .lang .annotation .Annotation ;
12
+ import java .lang .reflect .Parameter ;
13
+ import java .lang .reflect .Type ;
14
+ import java .util .HashMap ;
15
+ import java .util .List ;
16
+ import java .util .Map ;
17
+ import java .util .Optional ;
18
+ import java .util .logging .Logger ;
11
19
20
+ public final class ExecutionContextDataSource extends DataSource <ExecutionContext > implements MiddlewareContext {
12
21
private final String invocationId ;
13
22
private final TraceContext traceContext ;
14
23
private final RetryContext retryContext ;
@@ -18,14 +27,37 @@ public final class ExecutionContextDataSource extends DataSource<ExecutionContex
18
27
private final MethodBindInfo methodBindInfo ;
19
28
private final Class <?> containingClass ;
20
29
30
+ /*
31
+ Key is the name defined on customer function parameters. For ex:
32
+ @HttpTrigger(
33
+ name = "req",
34
+ methods = {HttpMethod.GET, HttpMethod.POST},
35
+ authLevel = AuthorizationLevel.ANONYMOUS)
36
+ HttpRequestMessage<Optional<String>> request,
37
+ Here name will be the "req".
38
+
39
+ Value is java.lang.reflect.Parameter type
40
+ */
41
+ private final Map <String , Parameter > parameterDefinitions ;
42
+
43
+ // currently the values are only Strings (resolved from grpc String values)
44
+ // but planning to support other types in the future
45
+ private final Map <String , Object > parameterValues ;
46
+
47
+ // these are parameters provided by the middleware, which will override the host provided parameter values
48
+ // currently the values are only Strings, but planning to support other types in the future
49
+ private final Map <String , Object > middlewareParameterValues = new HashMap <>();
50
+ private Object returnValue ;
51
+
52
+ //TODO: refactor class to have subclass dedicate to middleware to make logics clean
21
53
private static final DataOperations <ExecutionContext , Object > EXECONTEXT_DATA_OPERATIONS = new DataOperations <>();
22
54
static {
23
55
EXECONTEXT_DATA_OPERATIONS .addGenericOperation (ExecutionContext .class , DataOperations ::generalAssignment );
24
56
}
25
57
26
58
public ExecutionContextDataSource (String invocationId , TraceContext traceContext , RetryContext retryContext ,
27
- String funcname , BindingDataStore dataStore , MethodBindInfo methodBindInfo ,
28
- Class <?> containingClass ){
59
+ String funcname , BindingDataStore dataStore , MethodBindInfo methodBindInfo ,
60
+ Class <?> containingClass , List < ParameterBinding > parameterBindings ){
29
61
super (null , null , EXECONTEXT_DATA_OPERATIONS );
30
62
this .invocationId = invocationId ;
31
63
this .traceContext = traceContext ;
@@ -35,6 +67,8 @@ public ExecutionContextDataSource(String invocationId, TraceContext traceContext
35
67
this .dataStore = dataStore ;
36
68
this .methodBindInfo = methodBindInfo ;
37
69
this .containingClass = containingClass ;
70
+ this .parameterDefinitions = getParameterDefinitions (methodBindInfo );
71
+ this .parameterValues = resolveParameterValuesForMiddleware (parameterBindings );
38
72
this .setValue (this );
39
73
}
40
74
@@ -64,4 +98,78 @@ public MethodBindInfo getMethodBindInfo() {
64
98
public Class <?> getContainingClass () {
65
99
return containingClass ;
66
100
}
101
+
102
+ private static Map <String , Parameter > getParameterDefinitions (MethodBindInfo methodBindInfo ){
103
+ Map <String , Parameter > map = new HashMap <>();
104
+ for (ParamBindInfo paramBindInfo : methodBindInfo .getParams ()) {
105
+ map .put (paramBindInfo .getName (), paramBindInfo .getParameter ());
106
+ }
107
+ return map ;
108
+ }
109
+
110
+
111
+ //TODO: leverage stream to do the check
112
+ @ Override
113
+ public String getParameterName (String annotationSimpleClassName ){
114
+ for (Map .Entry <String , Parameter > entry : this .parameterDefinitions .entrySet ()){
115
+ if (hasAnnotation (entry .getValue (), annotationSimpleClassName )){
116
+ return entry .getKey ();
117
+ }
118
+ }
119
+ return null ;
120
+ }
121
+
122
+ private static boolean hasAnnotation (Parameter parameter , String annotationSimpleClassName ){
123
+ Annotation [] annotations = parameter .getAnnotations ();
124
+ for (Annotation annotation : annotations ) {
125
+ if (annotation .annotationType ().getSimpleName ().equals (annotationSimpleClassName )){
126
+ return true ;
127
+ }
128
+ }
129
+ return false ;
130
+ }
131
+
132
+ // TODO: Refactor the code in V5 to make resolve arguments logics before middleware invocation.
133
+ // for now only supporting String parameter values mapped to String values
134
+ private static Map <String , Object > resolveParameterValuesForMiddleware (List <ParameterBinding > parameterBindings ){
135
+ Map <String , Object > map = new HashMap <>();
136
+ for (ParameterBinding parameterBinding : parameterBindings ) {
137
+ TypedData typedData = parameterBinding .getData ();
138
+ if (typedData .getDataCase () == TypedData .DataCase .STRING ){
139
+ map .put (parameterBinding .getName (), typedData .getString ());
140
+ }
141
+ }
142
+ return map ;
143
+ }
144
+
145
+ @ Override
146
+ public Object getParameterValue (String name ) {
147
+ return this .parameterValues .get (name );
148
+ }
149
+
150
+ @ Override
151
+ public void updateParameterValue (String name , Object value ) {
152
+ this .middlewareParameterValues .put (name , value );
153
+ }
154
+
155
+ @ Override
156
+ public Object getReturnValue () {
157
+ return this .returnValue ;
158
+ }
159
+
160
+ @ Override
161
+ public void updateReturnValue (Object returnValue ) {
162
+ this .returnValue = returnValue ;
163
+ // set the return value that will be sent back to host
164
+ this .dataStore .setDataTargetValue (BindingDataStore .RETURN_NAME , this .returnValue );
165
+ }
166
+
167
+ public Optional <BindingData > getBindingData (String paramName , Type paramType ) {
168
+ Object inputValue = this .middlewareParameterValues .get (paramName );
169
+ if (inputValue != null ) {
170
+ return Optional .of (new BindingData (inputValue ));
171
+ }else {
172
+ return dataStore .getDataByName (paramName , paramType );
173
+ }
174
+ }
67
175
}
0 commit comments