1
1
package org .lowcoder .api .framework .plugin ;
2
2
3
- import static org .springframework .web .reactive .function .server .RequestPredicates .DELETE ;
4
- import static org .springframework .web .reactive .function .server .RequestPredicates .GET ;
5
- import static org .springframework .web .reactive .function .server .RequestPredicates .OPTIONS ;
6
- import static org .springframework .web .reactive .function .server .RequestPredicates .PATCH ;
7
- import static org .springframework .web .reactive .function .server .RequestPredicates .POST ;
8
- import static org .springframework .web .reactive .function .server .RequestPredicates .PUT ;
9
- import static org .springframework .web .reactive .function .server .RouterFunctions .route ;
10
-
11
- import java .lang .reflect .InvocationTargetException ;
12
- import java .lang .reflect .Method ;
13
3
import java .util .ArrayList ;
14
4
import java .util .Comparator ;
15
5
import java .util .LinkedHashMap ;
16
6
import java .util .List ;
17
7
import java .util .Map ;
18
8
19
9
import org .apache .commons .collections4 .CollectionUtils ;
20
- import org .apache .commons .lang3 .StringUtils ;
21
- import org .lowcoder .api .framework .plugin .data .PluginServerRequest ;
22
- import org .lowcoder .plugin .api .EndpointExtension ;
23
10
import org .lowcoder .plugin .api .LowcoderPlugin ;
24
11
import org .lowcoder .plugin .api .LowcoderServices ;
25
- import org .lowcoder .plugin .api .PluginEndpoint ;
26
- import org .lowcoder .plugin .api .data .EndpointRequest ;
27
- import org .lowcoder .plugin .api .data .EndpointResponse ;
28
- import org .lowcoder .sdk .exception .BaseException ;
29
- import org .springframework .core .ResolvableType ;
30
- import org .springframework .http .ResponseCookie ;
31
12
import org .springframework .stereotype .Component ;
32
- import org .springframework .web .reactive .function .server .RequestPredicate ;
33
- import org .springframework .web .reactive .function .server .RouterFunction ;
34
- import org .springframework .web .reactive .function .server .ServerResponse ;
35
- import org .springframework .web .reactive .function .server .ServerResponse .BodyBuilder ;
36
13
37
14
import jakarta .annotation .PostConstruct ;
38
15
import jakarta .annotation .PreDestroy ;
39
16
import lombok .RequiredArgsConstructor ;
40
17
import lombok .extern .slf4j .Slf4j ;
41
- import reactor .core .publisher .Mono ;
42
18
43
19
@ RequiredArgsConstructor
44
20
@ Component
@@ -49,7 +25,6 @@ public class LowcoderPluginManager
49
25
private final PluginLoader pluginLoader ;
50
26
51
27
private Map <String , LowcoderPlugin > plugins = new LinkedHashMap <>();
52
- private List <RouterFunction <ServerResponse >> routes = new ArrayList <>();
53
28
54
29
@ PostConstruct
55
30
private void loadPlugins ()
@@ -60,11 +35,8 @@ private void loadPlugins()
60
35
61
36
for (LowcoderPlugin plugin : sorted )
62
37
{
63
- if (plugin .load (lowcoderServices ))
64
- {
65
- log .info ("Plugin [{}] loaded successfully." , plugin .pluginId ());
66
- registerEndpoints (plugin );
67
- }
38
+ PluginExecutor executor = new PluginExecutor (plugin , lowcoderServices );
39
+ executor .start ();
68
40
}
69
41
}
70
42
@@ -84,11 +56,6 @@ public void unloadPlugins()
84
56
}
85
57
}
86
58
87
- public List <RouterFunction <ServerResponse >> getEndpoints ()
88
- {
89
- return this .routes ;
90
- }
91
-
92
59
public List <PluginInfo > getLoadedPluginsInfo ()
93
60
{
94
61
List <PluginInfo > infos = new ArrayList <>();
@@ -121,130 +88,6 @@ private void registerPlugins()
121
88
}
122
89
}
123
90
124
-
125
- private void registerEndpoints (LowcoderPlugin plugin )
126
- {
127
- if (CollectionUtils .isNotEmpty (plugin .endpoints ()))
128
- {
129
- for (PluginEndpoint endpoint : plugin .endpoints ())
130
- {
131
- Method [] handlers = endpoint .getClass ().getDeclaredMethods ();
132
- if (handlers != null && handlers .length > 0 )
133
- {
134
- for (Method handler : handlers )
135
- {
136
- registerEndpointHandler (plugin , endpoint , handler );
137
- }
138
- }
139
- }
140
- }
141
- }
142
-
143
- private void registerEndpointHandler (LowcoderPlugin plugin , PluginEndpoint endpoint , Method handler )
144
- {
145
- if (handler .isAnnotationPresent (EndpointExtension .class ))
146
- {
147
- if (checkHandlerMethod (handler ))
148
- {
149
-
150
- EndpointExtension endpointMeta = handler .getAnnotation (EndpointExtension .class );
151
- routes .add (route (createRequestPredicate (plugin , endpointMeta ), req -> {
152
- Mono <ServerResponse > result = null ;
153
- try
154
- {
155
- EndpointResponse response = (EndpointResponse )handler .invoke (endpoint , PluginServerRequest .fromServerRequest (req ));
156
- result = createServerResponse (response );
157
- }
158
- catch (IllegalAccessException | InvocationTargetException cause )
159
- {
160
- throw new BaseException ("Error running handler for [ " + endpointMeta .method () + ": " + endpointMeta .uri () + "] !" );
161
- }
162
- return result ;
163
- })
164
- );
165
- log .info ("Registered plugin endpoint: {} -> {} -> {}: {}" , plugin .pluginId (), endpoint .getClass ().getSimpleName (), endpointMeta .method (), endpointMeta .uri ());
166
- }
167
- else
168
- {
169
- log .error ("Cannot register plugin endpoint: {} -> {} -> {}! Handler method must be defined as: public Mono<ServerResponse> {}(ServerRequest request)" , plugin .pluginId (), endpoint .getClass ().getSimpleName (), handler .getName (), handler .getName ());
170
- }
171
- }
172
- }
173
-
174
- private Mono <ServerResponse > createServerResponse (EndpointResponse pluginResponse )
175
- {
176
- /** Create response with given status **/
177
- BodyBuilder builder = ServerResponse .status (pluginResponse .statusCode ());
178
-
179
- /** Set response headers **/
180
- if (pluginResponse .headers () != null && !pluginResponse .headers ().isEmpty ())
181
- {
182
- pluginResponse .headers ().entrySet ()
183
- .forEach (entry -> {
184
- builder .header (entry .getKey (), entry .getValue ().toArray (new String [] {}));
185
- });
186
-
187
- }
188
-
189
- /** Set cookies if available **/
190
- if (pluginResponse .cookies () != null && !pluginResponse .cookies ().isEmpty ())
191
- {
192
- pluginResponse .cookies ().values ()
193
- .forEach (cookies -> {
194
- cookies .forEach (cookie -> {
195
- builder .cookie (ResponseCookie .from (cookie .getKey (), cookie .getValue ()).build ());
196
- });
197
-
198
- });
199
- }
200
-
201
- /** Set response body if available **/
202
- if (pluginResponse .body () != null )
203
- {
204
- return builder .bodyValue (pluginResponse .body ());
205
- }
206
-
207
- return builder .build ();
208
- }
209
-
210
- private boolean checkHandlerMethod (Method method )
211
- {
212
- ResolvableType returnType = ResolvableType .forMethodReturnType (method );
213
-
214
- return (returnType .getRawClass ().isAssignableFrom (EndpointResponse .class )
215
- && method .getParameterCount () == 1
216
- && method .getParameterTypes ()[0 ].isAssignableFrom (EndpointRequest .class )
217
- );
218
- }
219
-
220
- private RequestPredicate createRequestPredicate (LowcoderPlugin plugin , EndpointExtension endpoint )
221
- {
222
- String basePath = "/plugins/" + plugin .pluginId ();
223
-
224
- switch (endpoint .method ())
225
- {
226
- case GET :
227
- return GET (pluginEndpointUri (basePath , endpoint .uri ()));
228
- case POST :
229
- return POST (pluginEndpointUri (basePath , endpoint .uri ()));
230
- case PUT :
231
- return PUT (pluginEndpointUri (basePath , endpoint .uri ()));
232
- case PATCH :
233
- return PATCH (pluginEndpointUri (basePath , endpoint .uri ()));
234
- case DELETE :
235
- return DELETE (pluginEndpointUri (basePath , endpoint .uri ()));
236
- case OPTIONS :
237
- return OPTIONS (pluginEndpointUri (basePath , endpoint .uri ()));
238
- }
239
- return null ;
240
- }
241
-
242
- private String pluginEndpointUri (String basePath , String uri )
243
- {
244
- return StringUtils .join (basePath , StringUtils .prependIfMissing (uri , "/" ));
245
- }
246
-
247
-
248
91
private record PluginInfo (
249
92
String id ,
250
93
String description ,
0 commit comments