CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jboss-shrinkwrap--shrinkwrap-impl-base

Common base implementations for the ShrinkWrap project enabling declarative assembly of Java archives (JAR, WAR, EAR, RAR) in code

Pending
Overview
Eval results
Files

assets.mddocs/

Asset Management

Asset management provides implementations for various content types that can be stored within archives, including service provider configurations, ZIP file entries, and other specialized asset types.

Core Asset Implementations

ServiceProviderAsset

Creates service provider configuration files for the Java ServiceLoader mechanism (META-INF/services/).

public class ServiceProviderAsset implements Asset

Constructors:

public ServiceProviderAsset(Class<?>... providerImpls)
public ServiceProviderAsset(String... providerImpls)

Key Methods:

public InputStream openStream()
public long getSize()

Usage Examples:

Single Service Implementation:

// Create service provider file for single implementation
ServiceProviderAsset asset = new ServiceProviderAsset(MyServiceImpl.class);
archive.addAsManifestResource(asset, "services/com.example.MyService");

Multiple Service Implementations:

// Create service provider file for multiple implementations
ServiceProviderAsset asset = new ServiceProviderAsset(
    DatabasePlugin.class,
    CachePlugin.class,
    LoggingPlugin.class
);
archive.addAsManifestResource(asset, "services/com.example.Plugin");

String-Based Configuration:

// Using class names as strings
ServiceProviderAsset asset = new ServiceProviderAsset(
    "com.example.impl.DefaultService",
    "com.example.impl.AlternativeService"
);

Generated Content Format: The asset generates content in the standard ServiceLoader format:

com.example.impl.DefaultService
com.example.impl.AlternativeService
# Comments are supported

ZipFileEntryAsset

Represents an asset backed by an entry from a ZIP file, enabling direct access to ZIP file contents.

public class ZipFileEntryAsset implements Asset

Constructors:

public ZipFileEntryAsset(ZipFile zipFile, ZipEntry entry)
public ZipFileEntryAsset(File zipFile, String entryName)

Key Methods:

public InputStream openStream()
public long getSize()
public long getLastModified()

Usage Examples:

Direct ZIP Entry Access:

ZipFile sourceZip = new ZipFile("source.zip");
ZipEntry entry = sourceZip.getEntry("config/app.properties");
ZipFileEntryAsset asset = new ZipFileEntryAsset(sourceZip, entry);

archive.addAsResource(asset, "app.properties");

File-Based ZIP Access:

ZipFileEntryAsset asset = new ZipFileEntryAsset(
    new File("dependencies.jar"), 
    "META-INF/MANIFEST.MF"
);
archive.addAsManifestResource(asset, "MANIFEST.MF");

Asset Utility Classes

IOUtilDelegator

Utility delegator for I/O operations on assets and streams.

public class IOUtilDelegator

Key Methods:

public static byte[] asByteArray(InputStream in)
public static String asUTF8String(InputStream in)
public static void copy(InputStream input, OutputStream output)

Usage:

// Convert asset to byte array
Asset asset = // ... get asset
byte[] content = IOUtilDelegator.asByteArray(asset.openStream());

// Convert asset to string
String textContent = IOUtilDelegator.asUTF8String(asset.openStream());

Advanced Asset Operations

Asset Composition

Creating composite assets from multiple sources:

public class CompositeAsset implements Asset {
    private final List<Asset> assets;
    
    public CompositeAsset(Asset... assets) {
        this.assets = Arrays.asList(assets);
    }
    
    @Override
    public InputStream openStream() {
        List<InputStream> streams = assets.stream()
            .map(Asset::openStream)
            .collect(Collectors.toList());
        return new SequenceInputStream(Collections.enumeration(streams));
    }
    
    @Override
    public long getSize() {
        return assets.stream().mapToLong(Asset::getSize).sum();
    }
}

// Usage: Combine multiple configuration files
CompositeAsset combined = new CompositeAsset(
    new ClassLoaderAsset("config-base.properties"),
    new ClassLoaderAsset("config-env.properties"),
    new FileAsset("config-local.properties")
);
archive.addAsResource(combined, "application.properties");

Asset Filtering

Filtering asset content during addition:

public class FilteredAsset implements Asset {
    private final Asset delegate;
    private final Predicate<String> lineFilter;
    
    public FilteredAsset(Asset delegate, Predicate<String> lineFilter) {
        this.delegate = delegate;
        this.lineFilter = lineFilter;
    }
    
    @Override
    public InputStream openStream() {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(delegate.openStream())
        );
        
        String filtered = reader.lines()
            .filter(lineFilter)
            .collect(Collectors.joining("\n"));
            
        return new ByteArrayInputStream(filtered.getBytes());
    }
}

// Usage: Filter out comments and empty lines
Asset original = new FileAsset("config.properties");
Asset filtered = new FilteredAsset(original, 
    line -> !line.trim().isEmpty() && !line.startsWith("#"));
archive.addAsResource(filtered, "config.properties");

Asset Transformation

Transforming asset content during processing:

public class TransformingAsset implements Asset {
    private final Asset source;
    private final Function<String, String> transformer;
    
    public TransformingAsset(Asset source, Function<String, String> transformer) {
        this.source = source;
        this.transformer = transformer;
    }
    
    @Override
    public InputStream openStream() {
        try (Scanner scanner = new Scanner(source.openStream())) {
            String content = scanner.useDelimiter("\\A").next();
            String transformed = transformer.apply(content);
            return new ByteArrayInputStream(transformed.getBytes());
        }
    }
}

// Usage: Replace placeholders in configuration files
Asset template = new ClassLoaderAsset("config-template.xml");
Asset configured = new TransformingAsset(template, content -> 
    content.replace("${app.name}", "MyApplication")
           .replace("${app.version}", "1.0.0"));
archive.addAsResource(configured, "config.xml");

Service Provider Management

Advanced Service Provider Configuration

Creating complex service provider configurations:

public class AdvancedServiceProviderAsset implements Asset {
    private final Map<String, List<String>> serviceProviders;
    
    public AdvancedServiceProviderAsset() {
        this.serviceProviders = new HashMap<>();
    }
    
    public AdvancedServiceProviderAsset addProvider(Class<?> service, Class<?>... implementations) {
        String serviceName = service.getName();
        List<String> impls = Arrays.stream(implementations)
            .map(Class::getName)
            .collect(Collectors.toList());
        serviceProviders.put(serviceName, impls);
        return this;
    }
    
    public void addToArchive(Archive<?> archive) {
        serviceProviders.forEach((service, implementations) -> {
            ServiceProviderAsset asset = new ServiceProviderAsset(
                implementations.toArray(new String[0])
            );
            archive.addAsManifestResource(asset, "services/" + service);
        });
    }
}

// Usage: Configure multiple services
AdvancedServiceProviderAsset serviceConfig = new AdvancedServiceProviderAsset()
    .addProvider(DatabaseService.class, MySQLService.class, PostgreSQLService.class)
    .addProvider(CacheService.class, RedisService.class, MemcachedService.class)
    .addProvider(LoggingService.class, Log4jService.class);

serviceConfig.addToArchive(archive);

Service Provider Discovery

Utilities for discovering existing service providers:

public class ServiceProviderDiscovery {
    public static Set<String> discoverProviders(Class<?> serviceClass, ClassLoader classLoader) {
        ServiceLoader<?> loader = ServiceLoader.load(serviceClass, classLoader);
        return StreamSupport.stream(loader.spliterator(), false)
            .map(provider -> provider.getClass().getName())
            .collect(Collectors.toSet());
    }
    
    public static ServiceProviderAsset createFromDiscovered(Class<?> serviceClass) {
        Set<String> providers = discoverProviders(serviceClass, 
            Thread.currentThread().getContextClassLoader());
        return new ServiceProviderAsset(providers.toArray(new String[0]));
    }
}

// Usage: Auto-discover and configure services
ServiceProviderAsset auto = ServiceProviderDiscovery.createFromDiscovered(Plugin.class);
archive.addAsManifestResource(auto, "services/com.example.Plugin");

Asset Validation

Content Validation

Validating asset content before inclusion:

public class ValidatingAsset implements Asset {
    private final Asset delegate;
    private final Predicate<byte[]> validator;
    
    public ValidatingAsset(Asset delegate, Predicate<byte[]> validator) {
        this.delegate = delegate;
        this.validator = validator;
    }
    
    @Override
    public InputStream openStream() {
        byte[] content = IOUtilDelegator.asByteArray(delegate.openStream());
        
        if (!validator.test(content)) {
            throw new IllegalStateException("Asset content validation failed");
        }
        
        return new ByteArrayInputStream(content);
    }
}

// Usage: Validate XML content
Predicate<byte[]> xmlValidator = content -> {
    try {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance()
            .newDocumentBuilder();
        builder.parse(new ByteArrayInputStream(content));
        return true;
    } catch (Exception e) {
        return false;
    }
};

Asset xmlAsset = new ValidatingAsset(
    new FileAsset("config.xml"), 
    xmlValidator
);

Performance Considerations

Lazy Loading

Assets support lazy loading to minimize memory usage:

// Assets are loaded on-demand
Asset asset = new FileAsset("large-file.dat");
archive.add(asset, "/data/large-file.dat");

// Content is not loaded until openStream() is called
InputStream stream = archive.get("/data/large-file.dat")
    .getAsset()
    .openStream();

Memory Management

Efficient memory usage with streaming operations:

// Stream large assets without loading entirely into memory
public static void copyLargeAsset(Asset source, OutputStream target) {
    try (InputStream input = source.openStream()) {
        IOUtilDelegator.copy(input, target);
    }
}

Asset Caching

Caching for frequently accessed assets:

public class CachedAsset implements Asset {
    private final Asset delegate;
    private byte[] cachedContent;
    
    public CachedAsset(Asset delegate) {
        this.delegate = delegate;
    }
    
    @Override
    public synchronized InputStream openStream() {
        if (cachedContent == null) {
            cachedContent = IOUtilDelegator.asByteArray(delegate.openStream());
        }
        return new ByteArrayInputStream(cachedContent);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-jboss-shrinkwrap--shrinkwrap-impl-base

docs

archive-bases.md

assets.md

containers.md

import-export.md

index.md

specifications.md

utilities.md

tile.json