1616
1717package com .google .adk .maven ;
1818
19+ import autovalue .shaded .com .google .common .collect .ImmutableList ;
20+ import com .google .adk .plugins .BasePlugin ;
1921import com .google .adk .utils .ComponentRegistry ;
2022import com .google .adk .web .AdkWebServer ;
23+ import com .google .adk .web .AgentLoader ;
24+ import com .google .common .base .Strings ;
2125import java .io .IOException ;
2226import java .lang .reflect .Field ;
2327import java .net .MalformedURLException ;
@@ -180,6 +184,30 @@ public class WebMojo extends AbstractMojo {
180184 @ Parameter (property = "registry" )
181185 private String registry ;
182186
187+ /**
188+ * Comma-separated list of additional plugin classes to load.
189+ *
190+ * <p>This parameter allows users to specify extra plugins that extend BasePlugin. Plugins provide
191+ * global callbacks for logging, monitoring, replay, caching, or modifying agent behaviors. These
192+ * are additional to any plugins configured by the user's code.
193+ *
194+ * <p>Each plugin reference can be either:
195+ *
196+ * <ul>
197+ * <li><strong>Static field reference:</strong> {@code com.example.MyPlugin.INSTANCE}
198+ * <li><strong>Class name:</strong> {@code com.example.MyPlugin} (requires default constructor)
199+ * </ul>
200+ *
201+ * <p>Example:
202+ *
203+ * <pre>{@code
204+ * mvn google-adk:web -Dagents=... -DextraPlugins=com.google.adk.plugins.ReplayPlugin
205+ * mvn google-adk:web -Dagents=... -DextraPlugins=com.google.adk.plugins.ReplayPlugin,com.example.CustomPlugin
206+ * }</pre>
207+ */
208+ @ Parameter (property = "extraPlugins" )
209+ private String extraPlugins ;
210+
183211 private ConfigurableApplicationContext applicationContext ;
184212 private URLClassLoader projectClassLoader ;
185213
@@ -205,18 +233,22 @@ public void execute() throws MojoExecutionException, MojoFailureException {
205233
206234 // Load and instantiate the AgentLoader
207235 getLog ().info ("Loading agent loader: " + agents );
208- com .google .adk .web .AgentLoader provider = loadAgentProvider ();
236+ AgentLoader provider = loadAgentProvider ();
237+
238+ // Load extra plugins if specified
239+ final List <BasePlugin > extraPluginInstances = loadExtraPlugins ();
209240
210241 // Set up system properties for Spring Boot
211242 setupSystemProperties ();
212243
213244 // Start the Spring Boot application with custom agent provider
214245 SpringApplication app = new SpringApplication (AdkWebServer .class );
215246
216- // Add the agent provider as a bean
247+ // Add the agent provider and extra plugins as beans
217248 app .addInitializers (
218249 ctx -> {
219250 ctx .getBeanFactory ().registerSingleton ("agentLoader" , provider );
251+ ctx .getBeanFactory ().registerSingleton ("extraPlugins" , extraPluginInstances );
220252 });
221253
222254 getLog ().info ("Starting Spring Boot application..." );
@@ -268,6 +300,7 @@ private void logConfiguration() {
268300 getLog ().info (" Server Host: " + host );
269301 getLog ().info (" Server Port: " + port );
270302 getLog ().info (" Registry: " + (registry != null ? registry : "default" ));
303+ getLog ().info (" Extra Plugins: " + (extraPlugins != null ? extraPlugins : "none" ));
271304 }
272305
273306 private void setupSystemProperties () {
@@ -401,7 +434,7 @@ private <T> T tryLoadFromConstructor(String className, Class<T> expectedType)
401434 }
402435 }
403436
404- private com . google . adk . web . AgentLoader loadAgentProvider () throws MojoExecutionException {
437+ private AgentLoader loadAgentProvider () throws MojoExecutionException {
405438 // First, check if agents parameter is a directory path
406439 Path agentsPath = Paths .get (agents );
407440 if (Files .isDirectory (agentsPath )) {
@@ -411,15 +444,56 @@ private com.google.adk.web.AgentLoader loadAgentProvider() throws MojoExecutionE
411444
412445 // Next, try to interpret as class.field syntax
413446 if (agents .contains ("." )) {
414- com .google .adk .web .AgentLoader provider =
415- tryLoadFromStaticField (agents , com .google .adk .web .AgentLoader .class );
447+ AgentLoader provider = tryLoadFromStaticField (agents , AgentLoader .class );
416448 if (provider != null ) {
417449 return provider ;
418450 }
419451 }
420452
421453 // Fallback to trying the entire string as a class name
422- return tryLoadFromConstructor (agents , com .google .adk .web .AgentLoader .class );
454+ return tryLoadFromConstructor (agents , AgentLoader .class );
455+ }
456+
457+ /**
458+ * Loads extra plugins from the comma-separated extraPlugins parameter.
459+ *
460+ * @return List of loaded plugin instances
461+ * @throws MojoExecutionException if plugins cannot be loaded
462+ */
463+ private ImmutableList <BasePlugin > loadExtraPlugins () throws MojoExecutionException {
464+ ImmutableList .Builder <BasePlugin > plugins = ImmutableList .builder ();
465+ String [] pluginNames = Strings .nullToEmpty (extraPlugins ).split ("," );
466+
467+ for (String name : pluginNames ) {
468+ name = name .trim ();
469+ if (name .isEmpty ()) {
470+ continue ;
471+ }
472+
473+ getLog ().info ("Loading plugin: " + name );
474+
475+ // Try to load as static field first
476+ BasePlugin plugin = null ;
477+ if (name .contains ("." )) {
478+ plugin = tryLoadFromStaticField (name , BasePlugin .class );
479+ }
480+
481+ // Fallback to constructor
482+ if (plugin == null ) {
483+ plugin = tryLoadFromConstructor (name , BasePlugin .class );
484+ }
485+
486+ if (plugin == null ) {
487+ throw new MojoExecutionException ("Failed to load plugin: " + name );
488+ }
489+
490+ plugins .add (plugin );
491+ getLog ()
492+ .info (
493+ String .format ("Successfully loaded plugin: `%s` from `%s`" , plugin .getName (), name ));
494+ }
495+
496+ return plugins .build ();
423497 }
424498
425499 /** Cleans up all resources including application context, classloader. */
0 commit comments