Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit acc402f

Browse files
committed
Merge remote-tracking branch 'origin/new_plugin_system' into merge-with-org
# Conflicts: # .gitignore # server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java # server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java # server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml # server/api-service/lowcoder-server/src/main/resources/selfhost/ce/application.yml # server/api-service/pom.xml
2 parents 2f38c64 + cdc42c6 commit acc402f

File tree

82 files changed

+2669
-767
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2669
-767
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@ client/node_modules/
99
client/packages/lowcoder-plugin-demo/.yarn/install-state.gz
1010
client/packages/lowcoder-plugin-demo/yarn.lock
1111
client/packages/lowcoder-plugin-demo/.yarn/cache/@types-node-npm-16.18.68-56f72825c0-094ae9ed80.zip
12-
.DS_Store
13-
.DS_Store
12+
application-dev.yml

deploy/docker/Dockerfile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,21 @@
22
## Build Lowcoder api-service application
33
##
44
FROM maven:3.9-eclipse-temurin-17 AS build-api-service
5+
6+
# Clone and build lowcoder-plugin-api
7+
RUN mkdir -p /build/plugin-api \
8+
&& cd /build/plugin-api \
9+
&& git clone https://[email protected]/Lowcoder-Pro/lowcoder-plugin-api.git .
10+
11+
WORKDIR /build/plugin-api
12+
RUN --mount=type=cache,target=/root/.m2 mvn -f pom.xml clean install -DskipTests
13+
514
COPY ./server/api-service /lowcoder-server
615
WORKDIR /lowcoder-server
716
RUN --mount=type=cache,target=/root/.m2 mvn -f pom.xml clean package -DskipTests
817

918
# Create required folder structure
10-
RUN mkdir -p /lowcoder/api-service/plugins /lowcoder/api-service/config /lowcoder/api-service/logs
19+
RUN mkdir -p /lowcoder/api-service/plugins /lowcoder/api-service/config /lowcoder/api-service/logs /lowcoder/plugins
1120

1221
# Define lowcoder main jar and plugin jars
1322
ARG JAR_FILE=/lowcoder-server/lowcoder-server/target/lowcoder-server-*.jar
@@ -202,6 +211,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-instal
202211

203212
# Add lowcoder api-service
204213
COPY --chown=lowcoder:lowcoder --from=lowcoder-ce-api-service /lowcoder/api-service /lowcoder/api-service
214+
RUN mkdir -p /lowcoder/plugins/ && chown lowcoder:lowcoder /lowcoder/plugins/
215+
COPY --chown=lowcoder:lowcoder enterprise-plugin-0.0.1.jar /lowcoder/plugins/enterprise-plugin-0.0.1.jar
205216

206217
# Add lowcoder node-service
207218
COPY --chown=lowcoder:lowcoder --from=lowcoder-ce-node-service /lowcoder/node-service /lowcoder/node-service

deploy/docker/api-service/entrypoint.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ echo
2828

2929
cd /lowcoder/api-service
3030
exec gosu ${USER_ID}:${GROUP_ID} ${JAVA_HOME}/bin/java \
31+
-Djava.util.prefs.userRoot=/tmp \
3132
-Djava.security.egd=file:/dev/./urandom \
3233
-Dhttps.protocols=TLSv1.1,TLSv1.2 \
3334
-Dlog4j2.formatMsgNoLookups=true \

server/api-service/PLUGIN.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Lowcoder plugin system (WIP)
2+
3+
This is an ongoing effort to refactor current plugin system based on pf4j library.
4+
5+
## Reasoning
6+
7+
1. create a cleaner and simpler plugin system with clearly defined purpose(s) (new endpoints, new datasource types, etc..)
8+
2. lowcoder does not need live plugin loading/reloading/unloading/updates, therefore the main feature of pf4j is rendered useless, in fact it adds a lot of complexity due to classloaders used for managing plugins (especially in spring/boot applications)
9+
3. simpler and easier plugin detection - just a jar with a class implementing a common interface (be it a simple pojo project or a complex spring/boot implementation)
10+
11+
## How it works
12+
13+
The main entrypoint for plugin system is in **lowcoder-server** module with class **org.lowcoder.api.framework.configuration.PluginConfiguration**
14+
It creates:
15+
- LowcoderPluginManager bean which is responsible for plugin lifecycle management
16+
- Adds plugin defined endpoints to lowcoder by creating **pluginEndpoints** bean
17+
- TODO: Adds plugin defined datasources to lowcoder by creating **pluginDatasources** bean
18+
19+
### lowcoder-plugin-api library
20+
21+
This library contains APIs for plugin implementations.
22+
It is used by both, lowcoder API server as well as all plugins.
23+
24+
### PluginLoader
25+
26+
The sole purpose of a PluginLoader is to find plugin candidates and load them into VM.
27+
There is currently one implementation that based on paths - **PathBasedPluginLoader**, it:
28+
- looks in folders and subfolders defined in **application.yaml** - entries can point to a folder or specific jar file. If a relative path is supplied, the location of lowcoder API server application jar is used as parent folder (when run in non-packaged state, eg. in IDE, it uses the folder where ServerApplication.class is generated)
29+
30+
```yaml
31+
common:
32+
plugin-dirs:
33+
- plugins
34+
- /some/custom/path/myGreatPlugin.jar
35+
```
36+
- finds all **jar**(s) and inspects them for classes implementing **LowcoderPlugin** interface
37+
- instantiates all LowcoderPlugin implementations
38+
39+
### LowcoderPluginManager
40+
41+
The main job of plugin manager is to:
42+
- register plugins found and instantiated by **PluginLoader**
43+
- start registered plugins by calling **LowcoderPlugin.load()** method
44+
- create and register **RouterFunction**(s) for all loaded plugin endpoints
45+
- TODO: create and register datasources for all loaded plugin datasources
46+
47+
## Plugin project structure
48+
49+
Plugin jar can be structured in any way you like. It can be a plain java project, but also a spring/boot based project or based on any other framework.
50+
51+
It is composed from several parts:
52+
- class(es) implementing **LowcoderPlugin** interface
53+
- class(es) implementing **LowcoderEndpoint** interface, containing endpoint handler functions marked with **@EndpointExtension** annotation. These functions must obey following format:
54+
55+
```java
56+
@EndpointExtension(uri = <endpoint uri>, method = <HTTP method>)
57+
public Mono<ServerResponse> <handler name>(ServerRequest request)
58+
{
59+
... your endpoint logic implementation
60+
}
61+
62+
for example:
63+
64+
@EndpointExtension(uri = "/hello-world", method = Method.GET)
65+
public Mono<ServerResponse> helloWorld(ServerRequest request)
66+
{
67+
return ServerResponse.ok().body(Mono.just(Hello.builder().message("Hello world!").build()), Hello.class);
68+
}
69+
```
70+
- TODO: class(es) impelemting **LowcoderDatasource** interface
71+
72+
### LowcoderPlugin implementations
73+
74+
Methods of interest:
75+
- **pluginId()** - unique plugin ID - if a plugin with such ID is already loaded, subsequent plugins whith this ID will be ignored
76+
- **description()** - short plugin description
77+
- **load(ApplicationContext parentContext)** - is called during plugin startup - this is the place where you should completely initialize your plugin. If initialization fails, return false
78+
- **unload()** - is called during lowcoder API server shutdown - this is the place where you should release all resources
79+
- **endpoints()** - needs to contain all initialized **PluginEndpoints** you want to expose, for example:
80+
81+
```java
82+
@Override
83+
public List<PluginEndpoint> endpoints()
84+
{
85+
List<PluginEndpoint> endpoints = new ArrayList<>();
86+
87+
endpoints.add(new HelloWorldEndpoint());
88+
89+
return endpoints;
90+
}
91+
```
92+
- **pluginInfo()** - should return a record object with additional information about your plugin. It is serialized to JSON as part of the **/plugins** listing (see **"info"** object in this example):
93+
94+
```json
95+
[
96+
{
97+
"id": "example-plugin",
98+
"description": "Example plugin for lowcoder platform",
99+
"info": {}
100+
},
101+
{
102+
"id": "enterprise",
103+
"description": "Lowcoder enterprise plugin",
104+
"info": {
105+
"enabledFeatures": [
106+
"endpointApiUsage"
107+
]
108+
}
109+
}
110+
]
111+
```
112+
113+
## TODOs
114+
115+
1. Implement endpoint security - currently all plugin endpoints are public (probably by adding **security** attribute to **@EndpointExtension** and enforcing it)
116+
117+
118+
## QUESTIONS / CONSIDERATIONS
119+
120+
1. currently the plugin endpoints are prefixed with **/plugin/{pluginId}/** - this is hardcoded, do we want to make it configurable?
121+
122+
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?xml version="1.0"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
6+
<parent>
7+
<artifactId>lowcoder-root</artifactId>
8+
<groupId>org.lowcoder</groupId>
9+
<version>${revision}</version>
10+
</parent>
11+
12+
<modelVersion>4.0.0</modelVersion>
13+
<artifactId>lowcoder-dependencies</artifactId>
14+
<packaging>pom</packaging>
15+
16+
<dependencyManagement>
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-dependencies</artifactId>
21+
<version>3.1.2</version>
22+
<type>pom</type>
23+
<scope>import</scope>
24+
</dependency>
25+
26+
<dependency>
27+
<groupId>org.pf4j</groupId>
28+
<artifactId>pf4j</artifactId>
29+
<version>3.5.0</version>
30+
</dependency>
31+
32+
<dependency>
33+
<groupId>org.json</groupId>
34+
<artifactId>json</artifactId>
35+
<version>20230227</version>
36+
</dependency>
37+
38+
<dependency>
39+
<groupId>org.projectlombok</groupId>
40+
<artifactId>lombok</artifactId>
41+
<version>1.18.26</version>
42+
</dependency>
43+
44+
<dependency>
45+
<groupId>org.apache.commons</groupId>
46+
<artifactId>commons-text</artifactId>
47+
<version>1.10.0</version>
48+
</dependency>
49+
<dependency>
50+
<groupId>commons-io</groupId>
51+
<artifactId>commons-io</artifactId>
52+
<version>2.13.0</version>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.glassfish</groupId>
56+
<artifactId>javax.el</artifactId>
57+
<version>3.0.0</version>
58+
</dependency>
59+
<dependency>
60+
<groupId>javax.el</groupId>
61+
<artifactId>javax.el-api</artifactId>
62+
<version>3.0.0</version>
63+
</dependency>
64+
65+
<dependency>
66+
<groupId>org.eclipse.jgit</groupId>
67+
<artifactId>org.eclipse.jgit</artifactId>
68+
<version>6.5.0.202303070854-r</version>
69+
</dependency>
70+
71+
<dependency>
72+
<groupId>org.apache.commons</groupId>
73+
<artifactId>commons-collections4</artifactId>
74+
<version>4.4</version>
75+
</dependency>
76+
<dependency>
77+
<groupId>com.google.guava</groupId>
78+
<artifactId>guava</artifactId>
79+
<version>30.0-jre</version>
80+
</dependency>
81+
82+
<dependency>
83+
<groupId>tv.twelvetone.rjson</groupId>
84+
<artifactId>rjson</artifactId>
85+
<version>1.3.1-SNAPSHOT</version>
86+
</dependency>
87+
<dependency>
88+
<groupId>org.jetbrains.kotlin</groupId>
89+
<artifactId>kotlin-stdlib-jdk7</artifactId>
90+
<version>1.6.21</version>
91+
</dependency>
92+
93+
<dependency>
94+
<groupId>com.jayway.jsonpath</groupId>
95+
<artifactId>json-path</artifactId>
96+
<version>2.7.0</version>
97+
</dependency>
98+
<dependency>
99+
<groupId>com.github.ben-manes.caffeine</groupId>
100+
<artifactId>caffeine</artifactId>
101+
<version>3.0.5</version>
102+
</dependency>
103+
<dependency>
104+
<groupId>es.moki.ratelimitj</groupId>
105+
<artifactId>ratelimitj-core</artifactId>
106+
<version>0.7.0</version>
107+
</dependency>
108+
<dependency>
109+
<groupId>com.github.spullara.mustache.java</groupId>
110+
<artifactId>compiler</artifactId>
111+
<version>0.9.6</version>
112+
</dependency>
113+
114+
<dependency>
115+
<groupId>es.moki.ratelimitj</groupId>
116+
<artifactId>ratelimitj-redis</artifactId>
117+
<version>0.7.0</version>
118+
</dependency>
119+
120+
<dependency>
121+
<groupId>io.projectreactor</groupId>
122+
<artifactId>reactor-core</artifactId>
123+
<version>3.4.29</version>
124+
</dependency>
125+
126+
<dependency>
127+
<groupId>org.pf4j</groupId>
128+
<artifactId>pf4j-spring</artifactId>
129+
<version>0.8.0</version>
130+
</dependency>
131+
132+
<dependency>
133+
<groupId>com.querydsl</groupId>
134+
<artifactId>querydsl-apt</artifactId>
135+
<version>5.0.0</version>
136+
</dependency>
137+
138+
<dependency>
139+
<groupId>io.sentry</groupId>
140+
<artifactId>sentry-spring-boot-starter</artifactId>
141+
<version>3.1.2</version>
142+
</dependency>
143+
144+
<dependency>
145+
<groupId>org.jgrapht</groupId>
146+
<artifactId>jgrapht-core</artifactId>
147+
<version>1.5.0</version>
148+
</dependency>
149+
150+
<dependency>
151+
<groupId>javax.xml.bind</groupId>
152+
<artifactId>jaxb-api</artifactId>
153+
<version>2.3.1</version>
154+
</dependency>
155+
<dependency>
156+
<groupId>javax.activation</groupId>
157+
<artifactId>activation</artifactId>
158+
<version>1.1.1</version>
159+
</dependency>
160+
<!-- no more than 2.3.3-->
161+
<dependency>
162+
<groupId>org.glassfish.jaxb</groupId>
163+
<artifactId>jaxb-runtime</artifactId>
164+
<version>2.3.3</version>
165+
</dependency>
166+
167+
<dependency>
168+
<groupId>com.github.cloudyrock.mongock</groupId>
169+
<artifactId>mongock-bom</artifactId>
170+
<version>4.3.8</version>
171+
<type>pom</type>
172+
<scope>import</scope>
173+
</dependency>
174+
175+
<dependency>
176+
<groupId>io.projectreactor.tools</groupId>
177+
<artifactId>blockhound</artifactId>
178+
<version>1.0.6.RELEASE</version>
179+
</dependency>
180+
181+
<dependency>
182+
<groupId>jakarta.servlet</groupId>
183+
<artifactId>jakarta.servlet-api</artifactId>
184+
<version>6.0.0</version>
185+
</dependency>
186+
187+
<dependency>
188+
<groupId>io.projectreactor</groupId>
189+
<artifactId>reactor-test</artifactId>
190+
<version>3.3.5.RELEASE</version>
191+
</dependency>
192+
<dependency>
193+
<groupId>org.apache.httpcomponents</groupId>
194+
<artifactId>httpclient</artifactId>
195+
<version>4.5.14</version>
196+
</dependency>
197+
<dependency>
198+
<groupId>de.flapdoodle.embed</groupId>
199+
<artifactId>de.flapdoodle.embed.mongo.spring30x</artifactId>
200+
<version>4.7.0</version>
201+
</dependency>
202+
<dependency>
203+
<groupId>org.mockito</groupId>
204+
<artifactId>mockito-inline</artifactId>
205+
<version>5.2.0</version>
206+
<scope>test</scope>
207+
</dependency>
208+
<dependency>
209+
<groupId>javax.validation</groupId>
210+
<artifactId>validation-api</artifactId>
211+
<version>2.0.1.Final</version>
212+
</dependency>
213+
</dependencies>
214+
</dependencyManagement>
215+
216+
217+
</project>
218+

0 commit comments

Comments
 (0)