12
12
import java .io .IOException ;
13
13
import java .nio .file .Files ;
14
14
import java .nio .file .Path ;
15
- import java .util .ArrayList ;
16
- import java .util .Iterator ;
17
- import java .util .List ;
18
- import java .util .ServiceLoader ;
15
+ import java .util .*;
19
16
20
17
@ Slf4j
21
18
@ RequiredArgsConstructor
22
19
@ Component
23
- public class PathBasedPluginLoader implements PluginLoader
24
- {
20
+ public class PathBasedPluginLoader implements PluginLoader {
25
21
private final CommonConfig common ;
26
22
private final ApplicationHome applicationHome ;
27
-
23
+
24
+ // Cache for plugin JAR paths to avoid redundant filesystem scans
25
+ private static final Map <String , List <String >> cachedPluginJars = new HashMap <>();
26
+
28
27
@ Override
29
- public List <LowcoderPlugin > loadPlugins ()
30
- {
28
+ public List <LowcoderPlugin > loadPlugins () {
31
29
List <LowcoderPlugin > plugins = new ArrayList <>();
32
-
30
+
31
+ // Find plugin JARs using caching
33
32
List <String > pluginJars = findPluginsJars ();
34
- if (pluginJars .isEmpty ())
35
- {
33
+ if (pluginJars .isEmpty ()) {
34
+ log . debug ( "No plugin JARs found." );
36
35
return plugins ;
37
36
}
38
37
39
- for ( String pluginJar : pluginJars )
40
- {
38
+ // Load plugins from JARs
39
+ pluginJars . parallelStream (). forEach ( pluginJar -> {
41
40
log .debug ("Inspecting plugin jar candidate: {}" , pluginJar );
42
41
List <LowcoderPlugin > loadedPlugins = loadPluginCandidates (pluginJar );
43
- if (loadedPlugins .isEmpty ())
44
- {
42
+ if (loadedPlugins .isEmpty ()) {
45
43
log .debug (" - no plugins found in the jar file" );
44
+ } else {
45
+ synchronized (plugins ) {
46
+ plugins .addAll (loadedPlugins );
47
+ }
46
48
}
47
- else
48
- {
49
- for (LowcoderPlugin plugin : loadedPlugins )
50
- {
51
- plugins .add (plugin );
52
- }
53
- }
54
- }
55
-
49
+ });
50
+
56
51
return plugins ;
57
52
}
58
-
59
- protected List <String > findPluginsJars ()
60
- {
53
+
54
+ protected List <String > findPluginsJars () {
55
+ String cacheKey = common .getPluginDirs ().toString ();
56
+
57
+ // Use cached JAR paths if available
58
+ if (cachedPluginJars .containsKey (cacheKey )) {
59
+ log .debug ("Using cached plugin jar candidates for key: {}" , cacheKey );
60
+ return cachedPluginJars .get (cacheKey );
61
+ }
62
+
61
63
List <String > candidates = new ArrayList <>();
62
- if (CollectionUtils .isNotEmpty (common .getPluginDirs ()))
63
- {
64
- for (String pluginDir : common .getPluginDirs ())
65
- {
64
+ if (CollectionUtils .isNotEmpty (common .getPluginDirs ())) {
65
+ for (String pluginDir : common .getPluginDirs ()) {
66
66
final Path pluginPath = getAbsoluteNormalizedPath (pluginDir );
67
- if (pluginPath != null )
68
- {
67
+ if (pluginPath != null ) {
69
68
candidates .addAll (findPluginCandidates (pluginPath ));
70
69
}
71
70
}
72
71
}
73
-
72
+
73
+ // Cache the results
74
+ cachedPluginJars .put (cacheKey , candidates );
74
75
return candidates ;
75
76
}
76
77
77
-
78
- protected List <String > findPluginCandidates (Path pluginsDir )
79
- {
80
- List <String > pluginCandidates = new ArrayList <>();
81
- try
82
- {
83
- Files .walk (pluginsDir )
84
- .filter (Files ::isRegularFile )
85
- .filter (path -> StringUtils .endsWithIgnoreCase (path .toAbsolutePath ().toString (), ".jar" ))
86
- .forEach (path -> pluginCandidates .add (path .toString ()));
87
- }
88
- catch (IOException cause )
89
- {
78
+ protected List <String > findPluginCandidates (Path pluginsDir ) {
79
+ try {
80
+ return Files .walk (pluginsDir )
81
+ .filter (Files ::isRegularFile )
82
+ .filter (path -> StringUtils .endsWithIgnoreCase (path .toAbsolutePath ().toString (), ".jar" ))
83
+ .map (Path ::toString )
84
+ .toList (); // Use Java 16+ `toList()` for better performance
85
+ } catch (IOException cause ) {
90
86
log .error ("Error walking plugin folder! - {}" , cause .getMessage ());
87
+ return Collections .emptyList ();
91
88
}
92
-
93
- return pluginCandidates ;
94
89
}
95
-
96
- protected List <LowcoderPlugin > loadPluginCandidates (String pluginJar )
97
- {
90
+
91
+ protected List <LowcoderPlugin > loadPluginCandidates (String pluginJar ) {
98
92
List <LowcoderPlugin > pluginCandidates = new ArrayList <>();
99
93
100
- try
101
- {
94
+ try {
102
95
Path pluginPath = Path .of (pluginJar );
103
96
PluginClassLoader pluginClassLoader = new PluginClassLoader (pluginPath .getFileName ().toString (), pluginPath );
104
97
105
98
ServiceLoader <LowcoderPlugin > pluginServices = ServiceLoader .load (LowcoderPlugin .class , pluginClassLoader );
106
- if (pluginServices != null )
107
- {
108
- Iterator <LowcoderPlugin > pluginIterator = pluginServices .iterator ();
109
- while (pluginIterator .hasNext ())
110
- {
111
- LowcoderPlugin plugin = pluginIterator .next ();
99
+ if (pluginServices != null ) {
100
+ for (LowcoderPlugin plugin : pluginServices ) {
112
101
log .debug (" - loaded plugin: {} - {}" , plugin .pluginId (), plugin .description ());
113
102
pluginCandidates .add (plugin );
114
103
}
115
104
}
116
- }
117
- catch (Throwable cause )
118
- {
105
+ } catch (Throwable cause ) {
119
106
log .warn ("Error loading plugin!" , cause );
120
107
}
121
-
108
+
122
109
return pluginCandidates ;
123
110
}
124
-
125
- private Path getAbsoluteNormalizedPath (String path )
126
- {
127
- if (StringUtils .isNotBlank (path ))
128
- {
111
+
112
+ private Path getAbsoluteNormalizedPath (String path ) {
113
+ if (StringUtils .isNotBlank (path )) {
129
114
Path absPath = Path .of (path );
130
- if (!absPath .isAbsolute ())
131
- {
115
+ if (!absPath .isAbsolute ()) {
132
116
absPath = Path .of (applicationHome .getDir ().getAbsolutePath (), absPath .toString ());
133
117
}
134
118
return absPath .normalize ().toAbsolutePath ();
135
119
}
136
-
137
120
return null ;
138
121
}
139
- }
122
+ }
0 commit comments