15
15
*/
16
16
package com .netflix .hystrix .contrib .javanica .utils ;
17
17
18
+ import com .google .common .base .Function ;
18
19
import com .google .common .base .Optional ;
20
+ import com .netflix .hystrix .contrib .javanica .annotation .DefaultProperties ;
19
21
import com .netflix .hystrix .contrib .javanica .annotation .HystrixCommand ;
20
22
import com .netflix .hystrix .contrib .javanica .exception .FallbackDefinitionException ;
21
23
import org .apache .commons .lang3 .ArrayUtils ;
@@ -49,6 +51,8 @@ public static MethodProvider getInstance() {
49
51
return INSTANCE ;
50
52
}
51
53
54
+ private static final FallbackMethodFinder FALLBACK_METHOD_FINDER = new SpecificFallback (new DefaultCallback ());
55
+
52
56
private Map <Method , Method > cache = new ConcurrentHashMap <Method , Method >();
53
57
54
58
public FallbackMethod getFallbackMethod (Class <?> type , Method commandMethod ) {
@@ -58,35 +62,139 @@ public FallbackMethod getFallbackMethod(Class<?> type, Method commandMethod) {
58
62
/**
59
63
* Gets fallback method for command method.
60
64
*
61
- * @param type type
65
+ * @param enclosingType the enclosing class
62
66
* @param commandMethod the command method. in the essence it can be a fallback
63
67
* method annotated with HystrixCommand annotation that has a fallback as well.
64
68
* @param extended true if the given commandMethod was derived using additional parameter, otherwise - false
65
69
* @return new instance of {@link FallbackMethod} or {@link FallbackMethod#ABSENT} if there is no suitable fallback method for the given command
66
70
*/
67
- public FallbackMethod getFallbackMethod (Class <?> type , Method commandMethod , boolean extended ) {
71
+ public FallbackMethod getFallbackMethod (Class <?> enclosingType , Method commandMethod , boolean extended ) {
68
72
if (commandMethod .isAnnotationPresent (HystrixCommand .class )) {
69
- HystrixCommand hystrixCommand = commandMethod .getAnnotation (HystrixCommand .class );
70
- if (StringUtils .isNotBlank (hystrixCommand .fallbackMethod ())) {
71
- Class <?>[] parameterTypes = commandMethod .getParameterTypes ();
72
- if (extended && parameterTypes [parameterTypes .length - 1 ] == Throwable .class ) {
73
- parameterTypes = ArrayUtils .remove (parameterTypes , parameterTypes .length - 1 );
74
- }
75
- Class <?>[] exParameterTypes = Arrays .copyOf (parameterTypes , parameterTypes .length + 1 );
76
- exParameterTypes [parameterTypes .length ] = Throwable .class ;
77
- Optional <Method > exFallbackMethod = getMethod (type , hystrixCommand .fallbackMethod (), exParameterTypes );
78
- Optional <Method > fMethod = getMethod (type , hystrixCommand .fallbackMethod (),
79
- parameterTypes );
80
- Method method = exFallbackMethod .or (fMethod ).orNull ();
81
- if (method == null ) {
82
- throw new FallbackDefinitionException ("fallback method wasn't found: " + hystrixCommand .fallbackMethod () + "(" + Arrays .toString (parameterTypes ) + ")" );
83
- }
84
- return new FallbackMethod (method , exFallbackMethod .isPresent ());
85
- }
73
+ return FALLBACK_METHOD_FINDER .find (enclosingType , commandMethod , extended );
86
74
}
87
75
return FallbackMethod .ABSENT ;
88
76
}
89
77
78
+ private void getDefaultFallback (){
79
+
80
+ }
81
+
82
+ private String getClassLevelFallback (Class <?> enclosingClass ) {
83
+ if (enclosingClass .isAnnotationPresent (DefaultProperties .class )) {
84
+ return enclosingClass .getAnnotation (DefaultProperties .class ).defaultFallback ();
85
+ }
86
+ return StringUtils .EMPTY ;
87
+ }
88
+
89
+ private static class SpecificFallback extends FallbackMethodFinder {
90
+
91
+ public SpecificFallback (FallbackMethodFinder next ) {
92
+ super (next );
93
+ }
94
+
95
+ @ Override
96
+ boolean isSpecific () {
97
+ return true ;
98
+ }
99
+
100
+ @ Override
101
+ public String getFallbackName (Class <?> enclosingType , Method commandMethod ) {
102
+ return commandMethod .getAnnotation (HystrixCommand .class ).fallbackMethod ();
103
+ }
104
+
105
+ @ Override
106
+ boolean canHandle (Class <?> enclosingType , Method commandMethod ) {
107
+ return StringUtils .isNotBlank (getFallbackName (enclosingType , commandMethod ));
108
+ }
109
+ }
110
+
111
+ private static class DefaultCallback extends FallbackMethodFinder {
112
+ @ Override
113
+ boolean isDefault () {
114
+ return true ;
115
+ }
116
+
117
+ @ Override
118
+ public String getFallbackName (Class <?> enclosingType , Method commandMethod ) {
119
+ String commandDefaultFallback = commandMethod .getAnnotation (HystrixCommand .class ).defaultFallback ();
120
+ String classDefaultFallback = Optional .fromNullable (enclosingType .getAnnotation (DefaultProperties .class ))
121
+ .transform (new Function <DefaultProperties , String >() {
122
+ @ Override
123
+ public String apply (DefaultProperties input ) {
124
+ return input .defaultFallback ();
125
+ }
126
+ }).or (StringUtils .EMPTY );
127
+
128
+ return StringUtils .defaultIfEmpty (commandDefaultFallback , classDefaultFallback );
129
+ }
130
+
131
+ @ Override
132
+ boolean canHandle (Class <?> enclosingType , Method commandMethod ) {
133
+ return StringUtils .isNotBlank (getFallbackName (enclosingType , commandMethod ));
134
+ }
135
+ }
136
+
137
+ private static abstract class FallbackMethodFinder {
138
+ FallbackMethodFinder next ;
139
+
140
+ public FallbackMethodFinder () {
141
+ }
142
+
143
+ public FallbackMethodFinder (FallbackMethodFinder next ) {
144
+ this .next = next ;
145
+ }
146
+
147
+ boolean isDefault () {
148
+ return false ;
149
+ }
150
+
151
+ boolean isSpecific (){
152
+ return false ;
153
+ }
154
+
155
+ public abstract String getFallbackName (Class <?> enclosingType , Method commandMethod );
156
+
157
+ public FallbackMethod find (Class <?> enclosingType , Method commandMethod , boolean extended ) {
158
+ if (canHandle (enclosingType , commandMethod )) {
159
+ return doFind (enclosingType , commandMethod , extended );
160
+ } else if (next != null ) {
161
+ return next .find (enclosingType , commandMethod , extended );
162
+ } else {
163
+ return FallbackMethod .ABSENT ;
164
+ }
165
+ }
166
+
167
+ abstract boolean canHandle (Class <?> enclosingType , Method commandMethod );
168
+
169
+ private FallbackMethod doFind (Class <?> enclosingType , Method commandMethod , boolean extended ) {
170
+ String name = getFallbackName (enclosingType , commandMethod );
171
+ Class <?>[] fallbackParameterTypes = null ;
172
+ if (isDefault ()) {
173
+ fallbackParameterTypes = new Class [0 ];
174
+ } else {
175
+ fallbackParameterTypes = commandMethod .getParameterTypes ();
176
+ }
177
+
178
+ if (extended && fallbackParameterTypes [fallbackParameterTypes .length - 1 ] == Throwable .class ) {
179
+ fallbackParameterTypes = ArrayUtils .remove (fallbackParameterTypes , fallbackParameterTypes .length - 1 );
180
+ }
181
+
182
+ Class <?>[] extendedFallbackParameterTypes = Arrays .copyOf (fallbackParameterTypes ,
183
+ fallbackParameterTypes .length + 1 );
184
+ extendedFallbackParameterTypes [fallbackParameterTypes .length ] = Throwable .class ;
185
+
186
+ Optional <Method > exFallbackMethod = getMethod (enclosingType , name , extendedFallbackParameterTypes );
187
+ Optional <Method > fMethod = getMethod (enclosingType , name , fallbackParameterTypes );
188
+ Method method = exFallbackMethod .or (fMethod ).orNull ();
189
+ if (method == null ) {
190
+ throw new FallbackDefinitionException ("fallback method wasn't found: " + name + "(" + Arrays .toString (fallbackParameterTypes ) + ")" );
191
+ }
192
+ return new FallbackMethod (method , exFallbackMethod .isPresent (), isDefault ());
193
+ }
194
+
195
+ }
196
+
197
+
90
198
/**
91
199
* Gets method by name and parameters types using reflection,
92
200
* if the given type doesn't contain required method then continue applying this method for all super classes up to Object class.
@@ -96,7 +204,7 @@ public FallbackMethod getFallbackMethod(Class<?> type, Method commandMethod, boo
96
204
* @param parameterTypes the parameters types
97
205
* @return Some if method exists otherwise None
98
206
*/
99
- public Optional <Method > getMethod (Class <?> type , String name , Class <?>... parameterTypes ) {
207
+ public static Optional <Method > getMethod (Class <?> type , String name , Class <?>... parameterTypes ) {
100
208
Method [] methods = type .getDeclaredMethods ();
101
209
for (Method method : methods ) {
102
210
if (method .getName ().equals (name ) && Arrays .equals (method .getParameterTypes (), parameterTypes )) {
0 commit comments