bndlib: A Swiss Army Knife for OSGi providing comprehensive bundle manipulation and analysis capabilities
—
Low-level JAR file manipulation and resource handling for OSGi bundles, providing fine-grained control over bundle contents.
Represents a JAR file with OSGi-specific operations for reading, writing, and manipulating bundle contents.
/**
* Represents a JAR file with OSGi-specific operations
*/
public class Jar implements Closeable {
/** Create empty JAR */
public Jar(String name);
/** Create JAR from file */
public Jar(File file) throws IOException;
/** Create JAR from input stream */
public Jar(String name, InputStream in) throws IOException;
/** Add resource to JAR */
public void putResource(String path, Resource resource);
/** Get resource from JAR */
public Resource getResource(String path);
/** Remove resource from JAR */
public void remove(String path);
/** Write JAR to file */
public void write(File file) throws Exception;
/** Write JAR to output stream */
public void write(OutputStream out) throws IOException;
/** Get JAR manifest */
public Manifest getManifest() throws Exception;
/** Set JAR manifest */
public void setManifest(Manifest manifest);
/** Get bundle symbolic name from manifest */
public String getBsn();
/** Get bundle version from manifest */
public String getVersion();
/** Get all resource paths */
public Set<String> getResources();
/** Get resources matching pattern */
public Map<String, Resource> getResources(String pattern);
/** Get directories in JAR */
public Set<String> getDirectories();
/** Get JAR name */
public String getName();
/** Set JAR name */
public void setName(String name);
/** Get last modified time */
public long lastModified();
/** Close and clean up resources */
public void close();
}Usage Examples:
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Resource;
import java.util.jar.Manifest;
// Create and populate JAR
Jar jar = new Jar("mybundle");
// Set manifest
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Bundle-SymbolicName", "com.example.mybundle");
manifest.getMainAttributes().putValue("Bundle-Version", "1.0.0");
jar.setManifest(manifest);
// Add resources
jar.putResource("com/example/MyClass.class",
new FileResource(new File("target/classes/com/example/MyClass.class")));
jar.putResource("META-INF/MANIFEST.MF",
new ManifestResource(manifest));
// Write to file
jar.write(new File("mybundle.jar"));
jar.close();
// Read existing JAR
Jar existingJar = new Jar(new File("existing.jar"));
System.out.println("Bundle: " + existingJar.getBsn() + " v" + existingJar.getVersion());
// List all resources
for (String path : existingJar.getResources()) {
System.out.println("Resource: " + path);
}
existingJar.close();Interface representing a resource within a JAR file, providing access to content and metadata.
/**
* Represents a resource in a JAR file
*/
public interface Resource extends Closeable {
/** Open input stream to read resource content */
public InputStream openInputStream() throws IOException;
/** Write resource content to output stream */
public void write(OutputStream out) throws Exception;
/** Get last modified time */
public long lastModified();
/** Set extra data associated with resource */
public void setExtra(String extra);
/** Get extra data */
public String getExtra();
/** Get resource size */
public long size() throws Exception;
/** Close resource and clean up */
public void close();
}Standard resource implementations for different content types.
/**
* Resource backed by a file
*/
public class FileResource implements Resource {
public FileResource(File file);
public File getFile();
}
/**
* Resource with string content
*/
public class EmbeddedResource implements Resource {
public EmbeddedResource(byte[] data, long lastModified);
public EmbeddedResource(String data, long lastModified);
public byte[] getData();
}
/**
* Resource backed by URL
*/
public class URLResource implements Resource {
public URLResource(URL url);
public URL getURL();
}
/**
* Resource representing a JAR manifest
*/
public class ManifestResource implements Resource {
public ManifestResource(Manifest manifest);
public Manifest getManifest();
}
/**
* Resource from ZIP entry
*/
public class ZipResource implements Resource {
public ZipResource(ZipFile zip, ZipEntry entry);
public ZipEntry getEntry();
}Resource Usage Examples:
import aQute.bnd.osgi.*;
// Working with different resource types
Jar jar = new Jar("example");
// File resource
jar.putResource("config/app.properties",
new FileResource(new File("src/main/resources/app.properties")));
// String resource
String xmlContent = "<?xml version=\"1.0\"?><config></config>";
jar.putResource("META-INF/config.xml",
new EmbeddedResource(xmlContent, System.currentTimeMillis()));
// URL resource (from classpath)
URL resourceUrl = getClass().getResource("/template.txt");
jar.putResource("templates/default.txt",
new URLResource(resourceUrl));
// Read resource content
Resource configResource = jar.getResource("config/app.properties");
if (configResource != null) {
try (InputStream in = configResource.openInputStream()) {
Properties props = new Properties();
props.load(in);
System.out.println("Loaded " + props.size() + " properties");
}
}
jar.close();Advanced JAR manipulation and analysis utilities.
/**
* Utilities for JAR analysis and manipulation
*/
public class JarUtils {
/** Copy JAR with filtering */
public static void copy(Jar source, Jar dest, String pattern);
/** Merge multiple JARs */
public static Jar merge(Jar... jars) throws IOException;
/** Extract JAR to directory */
public static void extract(Jar jar, File targetDir) throws IOException;
/** Create JAR from directory */
public static Jar create(File sourceDir) throws IOException;
/** Compare JAR contents */
public static boolean equals(Jar jar1, Jar jar2);
/** Get JAR checksum */
public static String checksum(Jar jar) throws Exception;
}Classes for extracting and working with OSGi bundle metadata.
/**
* Bundle information extracted from manifest
*/
public class BundleInfo {
public String getSymbolicName();
public Version getVersion();
public String getName();
public String getDescription();
public String getVendor();
public List<String> getExportedPackages();
public List<String> getImportedPackages();
public List<String> getRequiredBundles();
public boolean isFragment();
public String getFragmentHost();
}
/**
* Utility for extracting bundle information
*/
public class BundleInfoReader {
/** Read bundle info from JAR */
public static BundleInfo read(Jar jar) throws Exception;
/** Read bundle info from file */
public static BundleInfo read(File bundleFile) throws Exception;
/** Read bundle info from manifest */
public static BundleInfo read(Manifest manifest);
}Complete JAR Processing Example:
import aQute.bnd.osgi.*;
import java.util.jar.Manifest;
// Complete JAR processing workflow
try {
// Create new bundle JAR
Jar bundle = new Jar("com.example.mybundle");
// Create manifest
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
manifest.getMainAttributes().putValue("Bundle-ManifestVersion", "2");
manifest.getMainAttributes().putValue("Bundle-SymbolicName", "com.example.mybundle");
manifest.getMainAttributes().putValue("Bundle-Version", "1.0.0");
manifest.getMainAttributes().putValue("Bundle-Name", "My Example Bundle");
manifest.getMainAttributes().putValue("Export-Package", "com.example.api;version=\"1.0\"");
manifest.getMainAttributes().putValue("Import-Package", "org.osgi.framework;version=\"[1.8,2)\"");
bundle.setManifest(manifest);
// Add class files
File classesDir = new File("target/classes");
if (classesDir.exists()) {
addDirectory(bundle, classesDir, "");
}
// Add resources
bundle.putResource("META-INF/spring/bundle-context.xml",
new FileResource(new File("src/main/resources/bundle-context.xml")));
// Write bundle
File outputFile = new File("target/mybundle-1.0.0.jar");
bundle.write(outputFile);
System.out.println("Created bundle: " + outputFile);
System.out.println("Bundle-SymbolicName: " + bundle.getBsn());
System.out.println("Bundle-Version: " + bundle.getVersion());
System.out.println("Resources: " + bundle.getResources().size());
bundle.close();
} catch (Exception e) {
System.err.println("Failed to create bundle: " + e.getMessage());
e.printStackTrace();
}
// Helper method to add directory recursively
private static void addDirectory(Jar jar, File dir, String path) throws IOException {
for (File file : dir.listFiles()) {
String filePath = path.isEmpty() ? file.getName() : path + "/" + file.getName();
if (file.isDirectory()) {
addDirectory(jar, file, filePath);
} else {
jar.putResource(filePath, new FileResource(file));
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-biz-a-qute-bnd--biz-a-qute-bndlib