Skip to content

Commit 0b54e90

Browse files
committed
WIP: intermediate changes
1 parent 8b30ced commit 0b54e90

File tree

1 file changed

+10
-231
lines changed

1 file changed

+10
-231
lines changed
Lines changed: 10 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -1,254 +1,33 @@
11
package 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;
13-
import java.util.ArrayList;
14-
import java.util.Comparator;
15-
import java.util.LinkedHashMap;
16-
import java.util.List;
173
import java.util.Map;
184

19-
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-
import org.lowcoder.plugin.api.LowcoderPlugin;
24-
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;
5+
import org.lowcoder.plugin.LowcoderPlugin;
6+
import org.lowcoder.sdk.config.CommonConfig;
7+
import org.springframework.boot.system.ApplicationHome;
8+
import org.springframework.context.ConfigurableApplicationContext;
319
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;
3610

3711
import jakarta.annotation.PostConstruct;
38-
import jakarta.annotation.PreDestroy;
3912
import lombok.RequiredArgsConstructor;
4013
import lombok.extern.slf4j.Slf4j;
41-
import reactor.core.publisher.Mono;
4214

4315
@RequiredArgsConstructor
4416
@Component
4517
@Slf4j
4618
public class LowcoderPluginManager
4719
{
48-
private final LowcoderServices lowcoderServices;
49-
private final PluginLoader pluginLoader;
50-
51-
private Map<String, LowcoderPlugin> plugins = new LinkedHashMap<>();
52-
private List<RouterFunction<ServerResponse>> routes = new ArrayList<>();
53-
54-
@PostConstruct
55-
private void loadPlugins()
56-
{
57-
registerPlugins();
58-
List<LowcoderPlugin> sorted = new ArrayList<>(plugins.values());
59-
sorted.sort(Comparator.comparing(LowcoderPlugin::loadOrder));
60-
61-
for (LowcoderPlugin plugin : sorted)
62-
{
63-
if (plugin.load(lowcoderServices))
64-
{
65-
log.info("Plugin [{}] loaded successfully.", plugin.pluginId());
66-
registerEndpoints(plugin);
67-
}
68-
}
69-
}
70-
71-
@PreDestroy
72-
public void unloadPlugins()
73-
{
74-
for (LowcoderPlugin plugin : plugins.values())
75-
{
76-
try
77-
{
78-
plugin.unload();
79-
}
80-
catch(Throwable cause)
81-
{
82-
log.warn("Error unloading plugin: {}!", plugin.pluginId(), cause);
83-
}
84-
}
85-
}
86-
87-
public List<RouterFunction<ServerResponse>> getEndpoints()
88-
{
89-
return this.routes;
90-
}
91-
92-
public List<PluginInfo> getLoadedPluginsInfo()
93-
{
94-
List<PluginInfo> infos = new ArrayList<>();
95-
for (LowcoderPlugin plugin : plugins.values())
96-
{
97-
infos.add(new PluginInfo(plugin.pluginId(), plugin.description(), plugin.pluginInfo()));
98-
}
99-
return infos;
100-
}
101-
102-
private void registerPlugins()
103-
{
104-
List<LowcoderPlugin> loaded = pluginLoader.loadPlugins();
105-
if (CollectionUtils.isNotEmpty(loaded))
106-
{
107-
for (LowcoderPlugin plugin : loaded)
108-
{
109-
if (!plugins.containsKey(plugin.pluginId()))
110-
{
111-
log.info("Registered plugin: {} ({})", plugin.pluginId(), plugin.getClass().getName());
112-
plugins.put(plugin.pluginId(), plugin);
113-
}
114-
else
115-
{
116-
log.warn("Plugin {} already registered (from: {}), skipping {}.", plugin.pluginId(),
117-
plugins.get(plugin.pluginId()).getClass().getName(),
118-
plugin.getClass().getName());
119-
}
120-
}
121-
}
122-
}
123-
20+
private final ConfigurableApplicationContext applicationContext;
21+
private final CommonConfig common;
22+
private final ApplicationHome applicationHome;
12423

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-
}
24+
private Map<String, LowcoderPlugin> plugins;
17325

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-
}
20926

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)
27+
@PostConstruct
28+
private void loadPlugins()
22129
{
222-
String basePath = "/plugins/" + plugin.pluginId();
22330

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;
24031
}
241-
242-
private String pluginEndpointUri(String basePath, String uri)
243-
{
244-
return StringUtils.join(basePath, StringUtils.prependIfMissing(uri, "/"));
245-
}
246-
247-
248-
private record PluginInfo(
249-
String id,
250-
String description,
251-
Object info
252-
) {}
25332

25433
}

0 commit comments

Comments
 (0)