1212import java .io .IOException ;
1313import java .nio .file .Files ;
1414import 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 .*;
1916
2017@ Slf4j
2118@ RequiredArgsConstructor
2219@ Component
23- public class PathBasedPluginLoader implements PluginLoader
24- {
20+ public class PathBasedPluginLoader implements PluginLoader {
2521 private final CommonConfig common ;
2622 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+
2827 @ Override
29- public List <LowcoderPlugin > loadPlugins ()
30- {
28+ public List <LowcoderPlugin > loadPlugins () {
3129 List <LowcoderPlugin > plugins = new ArrayList <>();
32-
30+
31+ // Find plugin JARs using caching
3332 List <String > pluginJars = findPluginsJars ();
34- if (pluginJars .isEmpty ())
35- {
33+ if (pluginJars .isEmpty ()) {
34+ log . debug ( "No plugin JARs found." );
3635 return plugins ;
3736 }
3837
39- for ( String pluginJar : pluginJars )
40- {
38+ // Load plugins from JARs
39+ pluginJars . parallelStream (). forEach ( pluginJar -> {
4140 log .debug ("Inspecting plugin jar candidate: {}" , pluginJar );
4241 List <LowcoderPlugin > loadedPlugins = loadPluginCandidates (pluginJar );
43- if (loadedPlugins .isEmpty ())
44- {
42+ if (loadedPlugins .isEmpty ()) {
4543 log .debug (" - no plugins found in the jar file" );
44+ } else {
45+ synchronized (plugins ) {
46+ plugins .addAll (loadedPlugins );
47+ }
4648 }
47- else
48- {
49- for (LowcoderPlugin plugin : loadedPlugins )
50- {
51- plugins .add (plugin );
52- }
53- }
54- }
55-
49+ });
50+
5651 return plugins ;
5752 }
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+
6163 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 ()) {
6666 final Path pluginPath = getAbsoluteNormalizedPath (pluginDir );
67- if (pluginPath != null )
68- {
67+ if (pluginPath != null ) {
6968 candidates .addAll (findPluginCandidates (pluginPath ));
7069 }
7170 }
7271 }
73-
72+
73+ // Cache the results
74+ cachedPluginJars .put (cacheKey , candidates );
7475 return candidates ;
7576 }
7677
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 ) {
9086 log .error ("Error walking plugin folder! - {}" , cause .getMessage ());
87+ return Collections .emptyList ();
9188 }
92-
93- return pluginCandidates ;
9489 }
95-
96- protected List <LowcoderPlugin > loadPluginCandidates (String pluginJar )
97- {
90+
91+ protected List <LowcoderPlugin > loadPluginCandidates (String pluginJar ) {
9892 List <LowcoderPlugin > pluginCandidates = new ArrayList <>();
9993
100- try
101- {
94+ try {
10295 Path pluginPath = Path .of (pluginJar );
10396 PluginClassLoader pluginClassLoader = new PluginClassLoader (pluginPath .getFileName ().toString (), pluginPath );
10497
10598 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 ) {
112101 log .debug (" - loaded plugin: {} - {}" , plugin .pluginId (), plugin .description ());
113102 pluginCandidates .add (plugin );
114103 }
115104 }
116- }
117- catch (Throwable cause )
118- {
105+ } catch (Throwable cause ) {
119106 log .warn ("Error loading plugin!" , cause );
120107 }
121-
108+
122109 return pluginCandidates ;
123110 }
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 )) {
129114 Path absPath = Path .of (path );
130- if (!absPath .isAbsolute ())
131- {
115+ if (!absPath .isAbsolute ()) {
132116 absPath = Path .of (applicationHome .getDir ().getAbsolutePath (), absPath .toString ());
133117 }
134118 return absPath .normalize ().toAbsolutePath ();
135119 }
136-
137120 return null ;
138121 }
139- }
122+ }
0 commit comments