Documentation Index
Fetch the complete documentation index at: https://platform.docs.zenoo.com/llms.txt
Use this file to discover all available pages before exploring further.
Plugin System in Zenoo Hub
The Zenoo Hub features a robust plugin system that empowers developers to extend the platform with custom connectors and components, enabling seamless integration with third-party services and rapid adaptation to evolving business needs.Overview
The plugin system allows you to package, deploy, and manage custom logic independently of the Hub core. Plugins can introduce new connectors, orchestration steps, or business logic, all while maintaining a clean separation from the main codebase.Benefits
- Extensibility: Add new features and integrations without modifying the Hub core.
- Modularity: Develop, test, and deploy plugins independently.
- Maintainability: Isolate customer-specific or experimental logic from the main platform.
- Rapid Innovation: Prototype and roll out new capabilities quickly.
Architecture
Plugins are loaded at runtime by the Hub, using a dedicated classloader to ensure isolation and prevent conflicts. Each plugin can declare its own dependencies, resources, and configuration.Types of Plugins
- Custom Connectors: Integrate with external APIs, databases, or services.
- Transport Customizers: Enhance HTTP transports with custom authentication, filters, circuit breakers, or advanced features.
- Hub Components: Add new orchestration steps, validators, or business logic.
Development Workflow
- Create a Plugin Project: Use the provided SDK or follow the Plugin Connector Development guide.
- Implement Plugin Logic: Write your custom connector or component, specifying dependencies as needed.
- Package the Plugin: Build a JAR (or other supported format) containing your code and resources.
- Test Locally: Use the Hub’s testing tools or a local instance to validate your plugin.
Example: Adding a New Hub Component as a Plugin
Let’s walk through creating a custom Hub component as a plugin usingcom.zenoo.hub.plugin.sdk.ComponentFactory.
1. Implement the Plugin Component
Create a Groovy class that implementsComponentFactory and uses the ComponentBuilder DSL to define your component logic:
- The
@Componentannotation registers this class as an OSGi component. - The
define()method returns aComponentBuilderusing a Groovy DSL to declare dependencies and exposed operations. - The
exposed('test')block defines an entry point namedtestfor this component.
2. Package the Plugin
- Ensure your build includes the necessary dependencies and OSGi metadata.
- Build your project as a JAR file (a fat/uber JAR if needed).
3. Deploy the Plugin
- Place the JAR in the Hub’s plugin directory or deploy it using the Hub’s deployment mechanism.
- The Hub will detect and load your new component, making it available in workflow definitions as
test(or the name you expose).
Example: Creating a Transport Customizer Plugin
Transport customizers allow you to enhance HTTP transports defined in DSL with advanced features while preserving the base configuration (baseUrl, authentication). This follows the decorator pattern where customizers add functionality without replacing the underlying transport.Use Cases for Transport Customizers
- Advanced Authentication: OAuth2 flows, mTLS, API key rotation
- Resilience Patterns: Circuit breakers, retry logic, fallback mechanisms
- Custom Headers: Dynamic headers, correlation IDs, API versioning
- Monitoring: Request/response logging, timing metrics, tracing
- Content Transformation: Custom codecs, request/response interceptors
1. Create a Typed Configuration Class
Define a configuration class implementingPluginConfig with JSR-303 validation:
- Use
@Datafrom Lombok for automatic getters/setters - Add JSR-303 validation annotations (
@NotNull,@Min,@Max, etc.) - Provide sensible defaults for optional fields
- No need for Jackson annotations (Hub handles mapping automatically)
2. Implement the Transport Customizer
Create a class implementingTransportCustomizer and register it as an OSGi component:
name(): Returns the unique identifier for this customizer within the pluginconfigType(): Returns the configuration class type for automatic mapping and validationcustomize(): Receives the pre-configuredbaseClient(with DSL baseUrl & auth) and your typed config- Always use
baseClient.mutate()to preserve DSL settings while adding enhancements - Return the unmodified
baseClientif no customization is needed
3. Using Transport Customizers in DSL
Define the transport in your DSL with base configuration, then reference the customizer:- Hub creates base
WebClientfrom DSL transport (baseUrl + bearer auth) - Hub looks up customizer by name
'custom-http' - Hub maps component
configtoHttpTransportConfigand validates it - Hub calls
customizer.customize(baseClient, typedConfig) - Your customizer adds filters using
mutate() - Enhanced
WebClientis used for HTTP requests
4. Build Configuration for OSGi
Configure your plugin’sbuild.gradle to exclude framework packages from OSGi imports:
- Exclude Spring and Reactor from Import-Package (they’re loaded via boot delegation)
'Service-Component': '*'enables OSGi Declarative Services- The
bnd.builderplugin generates proper OSGi metadata
5. Karaf Configuration
Ensure your Karafconfig.properties includes boot delegation for framework classes:
Deployment Process
- Deploy to Hub: Place the plugin artifact in the designated plugins directory or use the Hub’s deployment API.
- Activation: The Hub detects new plugins and loads them at runtime, making new components available for use in workflows.
- Hot Reload (if supported): Some environments allow plugins to be updated without restarting the Hub.
Versioning and Isolation
- Each plugin is versioned independently, allowing safe upgrades and rollbacks.
- Plugins run in isolated classloaders to avoid dependency conflicts.
Best Practices
General Plugin Development
- Keep plugins focused and single-purpose.
- Document plugin APIs and configuration options.
- Use semantic versioning for plugin releases.
- Test plugins thoroughly before deployment.
- Monitor plugin performance and errors using Hub’s observability tools.
Transport Customizer Best Practices
- Always use
baseClient.mutate()to preserve DSL configuration (baseUrl, auth) - Return unmodified baseClient when config is null or no customization needed
- Use typed configuration with
PluginConfigand JSR-303 validation for type safety - Avoid overriding DSL settings unless explicitly required by your use case
- Be cautious with logging - avoid exposing sensitive data (credentials, tokens, PII)
- Implement proper error handling with meaningful exceptions
- Consider thread safety - the returned WebClient is cached and used concurrently
- Add filters for cross-cutting concerns - logging, timing, custom headers
- Test with various DSL transport configurations to ensure decorator pattern works correctly
- Document which DSL settings your customizer depends on or modifies