11package org .lowcoder .api .framework .plugin ;
22
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 ;
133import java .util .ArrayList ;
144import java .util .Comparator ;
155import java .util .LinkedHashMap ;
166import java .util .List ;
177import java .util .Map ;
188
199import 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 ;
2310import org .lowcoder .plugin .api .LowcoderPlugin ;
2411import 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 ;
3112import 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 ;
3613
3714import jakarta .annotation .PostConstruct ;
3815import jakarta .annotation .PreDestroy ;
3916import lombok .RequiredArgsConstructor ;
4017import lombok .extern .slf4j .Slf4j ;
41- import reactor .core .publisher .Mono ;
4218
4319@ RequiredArgsConstructor
4420@ Component
@@ -49,7 +25,6 @@ public class LowcoderPluginManager
4925 private final PluginLoader pluginLoader ;
5026
5127 private Map <String , LowcoderPlugin > plugins = new LinkedHashMap <>();
52- private List <RouterFunction <ServerResponse >> routes = new ArrayList <>();
5328
5429 @ PostConstruct
5530 private void loadPlugins ()
@@ -60,11 +35,8 @@ private void loadPlugins()
6035
6136 for (LowcoderPlugin plugin : sorted )
6237 {
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 ();
6840 }
6941 }
7042
@@ -84,11 +56,6 @@ public void unloadPlugins()
8456 }
8557 }
8658
87- public List <RouterFunction <ServerResponse >> getEndpoints ()
88- {
89- return this .routes ;
90- }
91-
9259 public List <PluginInfo > getLoadedPluginsInfo ()
9360 {
9461 List <PluginInfo > infos = new ArrayList <>();
@@ -121,130 +88,6 @@ private void registerPlugins()
12188 }
12289 }
12390
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-
24891 private record PluginInfo (
24992 String id ,
25093 String description ,
0 commit comments