CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-biz-a-qute-bnd--biz-a-qute-bndlib

bndlib: A Swiss Army Knife for OSGi providing comprehensive bundle manipulation and analysis capabilities

Pending
Overview
Eval results
Files

plugin-architecture.mddocs/

Plugin Architecture

Extensible plugin system for customizing build processes and analysis, enabling powerful extensions to the bndlib functionality.

Capabilities

Plugin

Base interface for all BND plugins providing common configuration and reporting capabilities.

/**
 * Base interface for all BND plugins
 */
public interface Plugin {
    /** Set plugin properties from configuration */
    public void setProperties(Map<String,String> map);
    
    /** Set reporter for logging and error reporting */
    public void setReporter(Reporter processor);
}

AnalyzerPlugin

Plugin interface for custom class analysis during bundle creation and JAR processing.

/**
 * Plugin that can analyze classes during bundle creation
 */
public interface AnalyzerPlugin extends Plugin {
    /** Analyze JAR and modify analyzer state */
    public boolean analyzeJar(Analyzer analyzer) throws Exception;
    
    /** Get plugin priority for execution order */
    default int getPriority() { return 0; }
    
    /** Check if plugin applies to current context */
    default boolean applies(Analyzer analyzer) { return true; }
}

Usage Examples:

import aQute.bnd.service.AnalyzerPlugin;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Clazz;

// Custom analyzer plugin example
public class CustomAnalyzerPlugin implements AnalyzerPlugin {
    private String prefix = "custom";
    
    @Override
    public void setProperties(Map<String, String> map) {
        prefix = map.getOrDefault("prefix", "custom");
    }
    
    @Override
    public void setReporter(Reporter reporter) {
        this.reporter = reporter;
    }
    
    @Override
    public boolean analyzeJar(Analyzer analyzer) throws Exception {
        // Custom analysis logic
        for (Clazz clazz : analyzer.getClassspace().values()) {
            if (clazz.getClassName().toString().startsWith(prefix)) {
                // Mark for special processing
                analyzer.setProperty("Custom-Classes", 
                    analyzer.getProperty("Custom-Classes", "") + "," + clazz.getClassName());
            }
        }
        return false; // Don't stop processing other plugins
    }
}

// Register and use plugin
Analyzer analyzer = new Analyzer();
analyzer.getPlugins().add(new CustomAnalyzerPlugin());
analyzer.analyze();

BuilderPlugin

Plugin interface for custom build processing and bundle manipulation.

/**
 * Plugin for custom build processing
 */
public interface BuilderPlugin extends Plugin {
    /** Process builder before build */
    public void processBuild(Builder builder) throws Exception;
    
    /** Post-process built JAR */
    public void postProcess(Builder builder, Jar jar) throws Exception;
    
    /** Get plugin execution phase */
    default Phase getPhase() { return Phase.BUILD; }
}

/**
 * Build phases for plugin execution
 */
public enum Phase {
    PRE_BUILD,   // Before build starts
    BUILD,       // During build
    POST_BUILD   // After build completes
}

LauncherPlugin

Plugin interface for custom OSGi framework launchers and runtime environments.

/**
 * Plugin for custom OSGi launchers
 */
public interface LauncherPlugin extends Plugin {
    /** Launch OSGi framework with configuration */
    public int launch(ProjectLauncher launcher) throws Exception;
    
    /** Get launcher type identifier */
    public String getType();
    
    /** Check if launcher is available in current environment */
    public boolean isAvailable();
    
    /** Get launcher configuration */
    public Map<String, String> getConfiguration();
}

/**
 * Project launcher configuration
 */
public class ProjectLauncher {
    /** Get project being launched */
    public Project getProject();
    
    /** Get run bundles */
    public Collection<String> getRunBundles();
    
    /** Get framework */
    public String getRunFramework();
    
    /** Get JVM arguments */
    public List<String> getRunJVMArgs();
    
    /** Get program arguments */
    public List<String> getRunProgramArgs();
    
    /** Get run properties */
    public Map<String, String> getRunProperties();
}

VerifierPlugin

Plugin interface for custom bundle verification and validation.

/**
 * Plugin for custom bundle verification
 */
public interface VerifierPlugin extends Plugin {
    /** Verify bundle and report issues */
    public void verify(Analyzer analyzer) throws Exception;
    
    /** Get verification severity level */
    default Severity getSeverity() { return Severity.ERROR; }
    
    /** Check if verifier applies to bundle */
    default boolean applies(Analyzer analyzer) { return true; }
}

/**
 * Verification severity levels
 */
public enum Severity {
    INFO,     // Informational
    WARNING,  // Warning but not blocking
    ERROR     // Error that blocks build
}

Usage Examples:

import aQute.bnd.service.VerifierPlugin;
import aQute.bnd.osgi.Analyzer;

// Custom verifier plugin example
public class BundleNamingVerifier implements VerifierPlugin {
    private String requiredPrefix;
    
    @Override
    public void setProperties(Map<String, String> map) {
        requiredPrefix = map.get("required.prefix");
    }
    
    @Override
    public void setReporter(Reporter reporter) {
        this.reporter = reporter;
    }
    
    @Override
    public void verify(Analyzer analyzer) throws Exception {
        String bsn = analyzer.getBsn();
        if (requiredPrefix != null && !bsn.startsWith(requiredPrefix)) {
            analyzer.error("Bundle symbolic name must start with: " + requiredPrefix);
        }
        
        // Verify version format
        String version = analyzer.getProperty("Bundle-Version");
        if (version != null && !isValidVersion(version)) {
            analyzer.warning("Bundle version format may not be semantic: " + version);
        }
    }
    
    private boolean isValidVersion(String version) {
        return version.matches("\\d+\\.\\d+\\.\\d+(\\..+)?");
    }
}

Command Plugin

Plugin interface for adding custom commands to bnd tools.

/**
 * Plugin for custom bnd commands
 */
public interface CommandPlugin extends Plugin {
    /** Execute command with arguments */
    public void execute(String command, String[] args) throws Exception;
    
    /** Get supported commands */
    public String[] getCommands();
    
    /** Get command help text */
    public String getHelp(String command);
    
    /** Get command usage syntax */
    public String getUsage(String command);
}

Generate Plugin

Plugin interface for generating additional resources during build.

/**
 * Plugin for generating additional resources
 */
public interface GeneratePlugin extends Plugin {
    /** Generate resources for builder */
    public void generate(Builder builder) throws Exception;
    
    /** Get generator type */
    public String getType();
    
    /** Check if generator should run */
    default boolean shouldGenerate(Builder builder) { return true; }
}

Plugin Registry and Management

Classes for managing plugin registration and lifecycle.

/**
 * Registry for managing plugins
 */
public interface Registry {
    /** Get plugins of specified type */
    public <T extends Plugin> List<T> getPlugins(Class<T> type);
    
    /** Add plugin to registry */
    public void addPlugin(Plugin plugin);
    
    /** Remove plugin from registry */
    public void removePlugin(Plugin plugin);
    
    /** Get plugin by name */
    public Plugin getPlugin(String name);
    
    /** List all registered plugins */
    public List<Plugin> getPlugins();
}

/**
 * Plugin manager for loading and configuring plugins
 */
public class PluginManager {
    /** Load plugin from class name */
    public static Plugin loadPlugin(String className, ClassLoader loader) throws Exception;
    
    /** Configure plugin with properties */
    public static void configurePlugin(Plugin plugin, Map<String, String> properties);
    
    /** Validate plugin configuration */
    public static List<String> validatePlugin(Plugin plugin);
    
    /** Get plugin dependencies */
    public static List<String> getPluginDependencies(Plugin plugin);
}

Built-in Plugin Examples

Common built-in plugins that demonstrate plugin patterns.

/**
 * Spring XML processing plugin
 */
public class SpringXMLType implements AnalyzerPlugin {
    public boolean analyzeJar(Analyzer analyzer) throws Exception;
}

/**
 * JPA entity analysis plugin  
 */
public class JPAComponent implements AnalyzerPlugin {
    public boolean analyzeJar(Analyzer analyzer) throws Exception;
}

/**
 * Maven dependency plugin
 */
public class MavenDependencyPlugin implements BuilderPlugin {
    public void processBuild(Builder builder) throws Exception;
}

/**
 * Felix launcher plugin
 */
public class FelixLauncher implements LauncherPlugin {
    public int launch(ProjectLauncher launcher) throws Exception;
    public String getType() { return "felix"; }
}

Complete Plugin Development Example:

import aQute.bnd.service.*;
import aQute.bnd.osgi.*;

// Complete custom plugin example
public class ComprehensivePlugin implements AnalyzerPlugin, BuilderPlugin, VerifierPlugin {
    
    private Reporter reporter;
    private Map<String, String> properties = new HashMap<>();
    
    @Override
    public void setProperties(Map<String, String> map) {
        this.properties.putAll(map);
    }
    
    @Override
    public void setReporter(Reporter reporter) {
        this.reporter = reporter;
    }
    
    // AnalyzerPlugin implementation
    @Override
    public boolean analyzeJar(Analyzer analyzer) throws Exception {
        reporter.progress(0.1f, "Starting custom analysis");
        
        // Analyze classes for custom annotations
        for (Clazz clazz : analyzer.getClassspace().values()) {
            if (hasCustomAnnotation(clazz)) {
                String packageName = clazz.getClassName().getPackage();
                analyzer.getContained().put(
                    analyzer.getPackageRef(packageName), 
                    new Attrs()
                );
            }
        }
        
        reporter.progress(1.0f, "Custom analysis complete");
        return false;
    }
    
    // BuilderPlugin implementation  
    @Override
    public void processBuild(Builder builder) throws Exception {
        // Add custom manifest headers
        String customValue = properties.getOrDefault("custom.header", "default");
        builder.setProperty("X-Custom-Header", customValue);
        
        // Generate additional resources
        generateCustomResources(builder);
    }
    
    @Override
    public void postProcess(Builder builder, Jar jar) throws Exception {
        // Post-process the built JAR
        addCustomResources(jar);
    }
    
    // VerifierPlugin implementation
    @Override
    public void verify(Analyzer analyzer) throws Exception {
        // Verify custom requirements
        String requiredHeader = properties.get("required.header");
        if (requiredHeader != null) {
            String value = analyzer.getProperty(requiredHeader);
            if (value == null) {
                analyzer.error("Required header missing: " + requiredHeader);
            }
        }
        
        // Verify custom package exports
        verifyCustomExports(analyzer);
    }
    
    private boolean hasCustomAnnotation(Clazz clazz) throws Exception {
        // Check for custom annotation
        return clazz.annotations() != null && 
               clazz.annotations().contains("Lcom/example/CustomAnnotation;");
    }
    
    private void generateCustomResources(Builder builder) throws Exception {
        // Generate custom configuration files
        String config = generateConfiguration();
        builder.getJar().putResource("META-INF/custom-config.properties", 
            new EmbeddedResource(config, System.currentTimeMillis()));
    }
    
    private void addCustomResources(Jar jar) throws Exception {
        // Add additional resources to final JAR
        String readme = generateReadme();
        jar.putResource("README.txt", 
            new EmbeddedResource(readme, System.currentTimeMillis()));
    }
    
    private void verifyCustomExports(Analyzer analyzer) throws Exception {
        // Verify that API packages are properly exported
        Packages exports = analyzer.getExports();
        Packages contained = analyzer.getContained();
        
        for (PackageRef pkg : contained.keySet()) {
            if (pkg.getFQN().contains(".api.") && !exports.containsKey(pkg)) {
                analyzer.warning("API package not exported: " + pkg.getFQN());
            }
        }
    }
    
    private String generateConfiguration() {
        StringBuilder config = new StringBuilder();
        config.append("# Generated configuration\n");
        config.append("plugin.name=").append(getClass().getSimpleName()).append("\n");
        config.append("plugin.version=1.0.0\n");
        
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            config.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
        }
        
        return config.toString();
    }
    
    private String generateReadme() {
        return "This bundle was processed by " + getClass().getSimpleName() + 
               " plugin.\nGenerated at: " + new Date();
    }
}

// Plugin usage in workspace/project
public class PluginUsageExample {
    
    public void useCustomPlugin() throws Exception {
        // In a workspace or project context
        Workspace workspace = Workspace.getWorkspace(new File("."));
        
        // Configure and add plugin
        ComprehensivePlugin plugin = new ComprehensivePlugin();
        Map<String, String> config = new HashMap<>();
        config.put("custom.header", "MyCustomValue");
        config.put("required.header", "Bundle-Category");
        plugin.setProperties(config);
        plugin.setReporter(workspace);
        
        // Add to project
        Project project = workspace.getProject("my.bundle");
        project.addPlugin(plugin);
        
        // Build with plugin
        File[] built = project.build();
        System.out.println("Built with custom plugin: " + Arrays.toString(built));
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-biz-a-qute-bnd--biz-a-qute-bndlib

docs

api-comparison-diffing.md

core-osgi-processing.md

header-processing.md

index.md

jar-resource-management.md

plugin-architecture.md

repository-system.md

version-management.md

workspace-project-management.md

tile.json