bndlib: A Swiss Army Knife for OSGi providing comprehensive bundle manipulation and analysis capabilities
—
Pluggable repository architecture for artifact storage and dependency resolution, enabling flexible bundle management across different storage backends.
Base interface for all repository implementations providing artifact storage and retrieval capabilities.
/**
* Base interface for all repository implementations
*/
public interface RepositoryPlugin extends Plugin {
/** Get artifact file by bundle symbolic name and version */
public File get(String bsn, Version version, Map<String,String> properties) throws Exception;
/** List all bundle symbolic names matching regex pattern */
public List<String> list(String regex) throws Exception;
/** Get all available versions for a bundle symbolic name */
public SortedSet<Version> versions(String bsn) throws Exception;
/** Get repository name */
public String getName();
/** Get repository location */
public String getLocation();
/** Check if repository can write */
public boolean canWrite();
/** Store artifact in repository */
public PutResult put(Jar jar, PutOptions options) throws Exception;
/** Get repository tooltip/description */
public String tooltip(Object... target) throws Exception;
/** Get repository title */
public String getTitle(Object... target) throws Exception;
}
/**
* Result of put operation
*/
public class PutResult {
public File artifact;
public String digest;
public boolean isNew;
}
/**
* Options for put operation
*/
public class PutOptions {
public boolean allowSnapshots = false;
public File context;
public String type;
}Usage Examples:
import aQute.bnd.service.RepositoryPlugin;
import aQute.bnd.version.Version;
// Use repository plugin
RepositoryPlugin repo = workspace.getPlugin(RepositoryPlugin.class).get(0);
// List available bundles
List<String> bundles = repo.list("org\\.apache\\..*");
for (String bsn : bundles) {
System.out.println("Bundle: " + bsn);
// Get available versions
SortedSet<Version> versions = repo.versions(bsn);
System.out.println(" Versions: " + versions);
// Get latest version
if (!versions.isEmpty()) {
Version latest = versions.last();
File file = repo.get(bsn, latest, null);
if (file != null) {
System.out.println(" Latest: " + file);
}
}
}In-memory repository implementation for OSGi resources with capability and requirement matching.
/**
* In-memory repository of OSGi resources
*/
public class ResourcesRepository implements Repository {
/** Create empty repository */
public ResourcesRepository();
/** Add resource to repository */
public void add(Resource resource);
/** Add all resources from collection */
public void addAll(Collection<? extends Resource> resources);
/** Find providers for a requirement */
public Collection<Capability> findProviders(Requirement requirement);
/** Get all resources */
public Collection<Resource> getResources();
/** Remove resource */
public boolean remove(Resource resource);
/** Clear all resources */
public void clear();
/** Get repository size */
public int size();
}File-based repository implementation storing bundles in directory structure.
/**
* File-based repository implementation
*/
public class FileRepo implements RepositoryPlugin {
/** Create file repository at location */
public FileRepo(String name, File location, boolean readonly);
/** Set repository location */
public void setLocation(String location);
/** Get repository location */
public String getLocation();
/** Set readonly flag */
public void setReadonly(boolean readonly);
/** Check if repository is readonly */
public boolean isReadonly();
/** Get file for bundle */
public File get(String bsn, Version version, Map<String,String> properties) throws Exception;
/** Store bundle in repository */
public PutResult put(Jar jar, PutOptions options) throws Exception;
/** List bundles matching pattern */
public List<String> list(String regex) throws Exception;
/** Get versions for bundle */
public SortedSet<Version> versions(String bsn) throws Exception;
/** Refresh repository index */
public void refresh() throws Exception;
}Usage Examples:
import aQute.bnd.service.RepositoryPlugin.PutOptions;
import aQute.bnd.service.RepositoryPlugin.PutResult;
// Create file repository
FileRepo repo = new FileRepo("local", new File("repository"), false);
// Store bundle
Jar bundle = new Jar(new File("mybundle.jar"));
PutOptions options = new PutOptions();
options.allowSnapshots = true;
PutResult result = repo.put(bundle, options);
if (result.isNew) {
System.out.println("Stored new bundle: " + result.artifact);
} else {
System.out.println("Bundle already exists: " + result.artifact);
}
// Retrieve bundle
File retrieved = repo.get("com.example.mybundle",
Version.parseVersion("1.0.0"), null);
if (retrieved != null) {
System.out.println("Retrieved: " + retrieved);
}Classes for creating and managing repository indexes for efficient bundle discovery.
/**
* Creates repository indexes from bundle collections
*/
public class SimpleIndexer {
/** Index bundles to output stream */
public static void index(Set<File> bundles, OutputStream out,
Map<String,String> config) throws Exception;
/** Index single bundle */
public static Resource indexBundle(File bundle) throws Exception;
/** Create index from directory */
public static void indexDirectory(File directory, OutputStream out) throws Exception;
}
/**
* Repository index reader
*/
public class RepositoryIndexReader {
/** Read index from stream */
public static Collection<Resource> readIndex(InputStream in) throws Exception;
/** Read index from file */
public static Collection<Resource> readIndex(File indexFile) throws Exception;
/** Parse index XML */
public static Repository parseIndex(InputStream in) throws Exception;
}Support for remote repositories with HTTP-based access.
/**
* HTTP-based remote repository
*/
public class HttpRepository implements RepositoryPlugin {
/** Create HTTP repository */
public HttpRepository(String name, String url);
/** Set repository URL */
public void setUrl(String url);
/** Get repository URL */
public String getUrl();
/** Set authentication credentials */
public void setCredentials(String username, String password);
/** Set connection timeout */
public void setTimeout(int timeoutMs);
/** Enable/disable caching */
public void setCaching(boolean enabled);
/** Set cache directory */
public void setCacheDir(File cacheDir);
/** Download bundle */
public File get(String bsn, Version version, Map<String,String> properties) throws Exception;
/** Get remote index */
public Repository getIndex() throws Exception;
}Integration with Maven repositories for dependency resolution.
/**
* Maven repository integration
*/
public class MavenRepository implements RepositoryPlugin {
/** Create Maven repository */
public MavenRepository(String name, String url);
/** Set Maven repository URL */
public void setUrl(String url);
/** Set local repository location */
public void setLocal(File localRepo);
/** Resolve Maven artifact */
public File get(String bsn, Version version, Map<String,String> properties) throws Exception;
/** Convert OSGi coordinates to Maven */
public MavenCoordinate toMavenCoordinate(String bsn, Version version);
/** Convert Maven coordinate to OSGi */
public BundleCoordinate toBundleCoordinate(MavenCoordinate coord);
}
/**
* Maven artifact coordinates
*/
public class MavenCoordinate {
public String groupId;
public String artifactId;
public String version;
public String classifier;
public String type;
public String toString(); // groupId:artifactId:version[:classifier][@type]
}
/**
* OSGi bundle coordinates
*/
public class BundleCoordinate {
public String bundleSymbolicName;
public Version version;
public String toString(); // bsn;version=version
}Complete Repository System Example:
import aQute.bnd.service.RepositoryPlugin;
import aQute.bnd.osgi.repository.ResourcesRepository;
import aQute.lib.deployer.FileRepo;
// Complete repository system usage
public class RepositoryExample {
public void demonstrateRepositorySystem() throws Exception {
// Create different repository types
FileRepo localRepo = new FileRepo("local", new File("local-repo"), false);
HttpRepository centralRepo = new HttpRepository("central",
"https://repo1.maven.org/maven2");
MavenRepository mavenRepo = new MavenRepository("maven-central",
"https://repo1.maven.org/maven2");
// Store bundle in local repository
Jar myBundle = createBundle();
PutOptions options = new PutOptions();
options.allowSnapshots = true;
PutResult result = localRepo.put(myBundle, options);
System.out.println("Stored: " + result.artifact);
// Search across repositories
String[] repositories = {"local", "central", "maven-central"};
String targetBundle = "org.apache.commons.lang3";
for (String repoName : repositories) {
RepositoryPlugin repo = getRepository(repoName);
// List available versions
SortedSet<Version> versions = repo.versions(targetBundle);
if (!versions.isEmpty()) {
System.out.println(repoName + " has " + targetBundle +
" versions: " + versions);
// Get latest version
Version latest = versions.last();
File bundle = repo.get(targetBundle, latest, null);
if (bundle != null) {
System.out.println("Downloaded: " + bundle);
// Analyze downloaded bundle
analyzeBundle(bundle);
}
break; // Found it, stop searching
}
}
// Create in-memory repository for resolution
ResourcesRepository memRepo = new ResourcesRepository();
// Add resources to memory repository
memRepo.add(createResourceFromBundle(myBundle));
// Find providers for requirements
Requirement requirement = createRequirement("osgi.wiring.package",
"com.example.api");
Collection<Capability> providers = memRepo.findProviders(requirement);
System.out.println("Providers for requirement: " + providers.size());
// Create repository index
Set<File> bundles = new HashSet<>();
bundles.add(new File("bundle1.jar"));
bundles.add(new File("bundle2.jar"));
try (FileOutputStream indexOut = new FileOutputStream("repository.xml")) {
SimpleIndexer.index(bundles, indexOut, Collections.emptyMap());
}
System.out.println("Created repository index");
}
private Jar createBundle() throws Exception {
// Implementation to create a sample bundle
Jar jar = new Jar("example");
// ... add content
return jar;
}
private RepositoryPlugin getRepository(String name) {
// Implementation to get repository by name
return null;
}
private void analyzeBundle(File bundle) throws Exception {
try (Jar jar = new Jar(bundle)) {
System.out.println(" Bundle-SymbolicName: " + jar.getBsn());
System.out.println(" Bundle-Version: " + jar.getVersion());
}
}
private Resource createResourceFromBundle(Jar bundle) throws Exception {
// Convert bundle to OSGi resource
return null;
}
private Requirement createRequirement(String namespace, String name) {
// Create OSGi requirement
return null;
}
}Install with Tessl CLI
npx tessl i tessl/maven-biz-a-qute-bnd--biz-a-qute-bndlib