or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

archive-bases.mdassets.mdcontainers.mdimport-export.mdindex.mdspecifications.mdutilities.md

assets.mddocs/

0

# Asset Management

1

2

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.

3

4

## Core Asset Implementations

5

6

### ServiceProviderAsset

7

8

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

9

10

```java { .api }

11

public class ServiceProviderAsset implements Asset

12

```

13

14

**Constructors:**

15

```java { .api }

16

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

17

public ServiceProviderAsset(String... providerImpls)

18

```

19

20

**Key Methods:**

21

```java { .api }

22

public InputStream openStream()

23

public long getSize()

24

```

25

26

**Usage Examples:**

27

28

**Single Service Implementation:**

29

```java

30

// Create service provider file for single implementation

31

ServiceProviderAsset asset = new ServiceProviderAsset(MyServiceImpl.class);

32

archive.addAsManifestResource(asset, "services/com.example.MyService");

33

```

34

35

**Multiple Service Implementations:**

36

```java

37

// Create service provider file for multiple implementations

38

ServiceProviderAsset asset = new ServiceProviderAsset(

39

DatabasePlugin.class,

40

CachePlugin.class,

41

LoggingPlugin.class

42

);

43

archive.addAsManifestResource(asset, "services/com.example.Plugin");

44

```

45

46

**String-Based Configuration:**

47

```java

48

// Using class names as strings

49

ServiceProviderAsset asset = new ServiceProviderAsset(

50

"com.example.impl.DefaultService",

51

"com.example.impl.AlternativeService"

52

);

53

```

54

55

**Generated Content Format:**

56

The asset generates content in the standard ServiceLoader format:

57

```

58

com.example.impl.DefaultService

59

com.example.impl.AlternativeService

60

# Comments are supported

61

```

62

63

### ZipFileEntryAsset

64

65

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

66

67

```java { .api }

68

public class ZipFileEntryAsset implements Asset

69

```

70

71

**Constructors:**

72

```java { .api }

73

public ZipFileEntryAsset(ZipFile zipFile, ZipEntry entry)

74

public ZipFileEntryAsset(File zipFile, String entryName)

75

```

76

77

**Key Methods:**

78

```java { .api }

79

public InputStream openStream()

80

public long getSize()

81

public long getLastModified()

82

```

83

84

**Usage Examples:**

85

86

**Direct ZIP Entry Access:**

87

```java

88

ZipFile sourceZip = new ZipFile("source.zip");

89

ZipEntry entry = sourceZip.getEntry("config/app.properties");

90

ZipFileEntryAsset asset = new ZipFileEntryAsset(sourceZip, entry);

91

92

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

93

```

94

95

**File-Based ZIP Access:**

96

```java

97

ZipFileEntryAsset asset = new ZipFileEntryAsset(

98

new File("dependencies.jar"),

99

"META-INF/MANIFEST.MF"

100

);

101

archive.addAsManifestResource(asset, "MANIFEST.MF");

102

```

103

104

## Asset Utility Classes

105

106

### IOUtilDelegator

107

108

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

109

110

```java { .api }

111

public class IOUtilDelegator

112

```

113

114

**Key Methods:**

115

```java { .api }

116

public static byte[] asByteArray(InputStream in)

117

public static String asUTF8String(InputStream in)

118

public static void copy(InputStream input, OutputStream output)

119

```

120

121

**Usage:**

122

```java

123

// Convert asset to byte array

124

Asset asset = // ... get asset

125

byte[] content = IOUtilDelegator.asByteArray(asset.openStream());

126

127

// Convert asset to string

128

String textContent = IOUtilDelegator.asUTF8String(asset.openStream());

129

```

130

131

## Advanced Asset Operations

132

133

### Asset Composition

134

135

Creating composite assets from multiple sources:

136

137

```java

138

public class CompositeAsset implements Asset {

139

private final List<Asset> assets;

140

141

public CompositeAsset(Asset... assets) {

142

this.assets = Arrays.asList(assets);

143

}

144

145

@Override

146

public InputStream openStream() {

147

List<InputStream> streams = assets.stream()

148

.map(Asset::openStream)

149

.collect(Collectors.toList());

150

return new SequenceInputStream(Collections.enumeration(streams));

151

}

152

153

@Override

154

public long getSize() {

155

return assets.stream().mapToLong(Asset::getSize).sum();

156

}

157

}

158

159

// Usage: Combine multiple configuration files

160

CompositeAsset combined = new CompositeAsset(

161

new ClassLoaderAsset("config-base.properties"),

162

new ClassLoaderAsset("config-env.properties"),

163

new FileAsset("config-local.properties")

164

);

165

archive.addAsResource(combined, "application.properties");

166

```

167

168

### Asset Filtering

169

170

Filtering asset content during addition:

171

172

```java

173

public class FilteredAsset implements Asset {

174

private final Asset delegate;

175

private final Predicate<String> lineFilter;

176

177

public FilteredAsset(Asset delegate, Predicate<String> lineFilter) {

178

this.delegate = delegate;

179

this.lineFilter = lineFilter;

180

}

181

182

@Override

183

public InputStream openStream() {

184

BufferedReader reader = new BufferedReader(

185

new InputStreamReader(delegate.openStream())

186

);

187

188

String filtered = reader.lines()

189

.filter(lineFilter)

190

.collect(Collectors.joining("\n"));

191

192

return new ByteArrayInputStream(filtered.getBytes());

193

}

194

}

195

196

// Usage: Filter out comments and empty lines

197

Asset original = new FileAsset("config.properties");

198

Asset filtered = new FilteredAsset(original,

199

line -> !line.trim().isEmpty() && !line.startsWith("#"));

200

archive.addAsResource(filtered, "config.properties");

201

```

202

203

### Asset Transformation

204

205

Transforming asset content during processing:

206

207

```java

208

public class TransformingAsset implements Asset {

209

private final Asset source;

210

private final Function<String, String> transformer;

211

212

public TransformingAsset(Asset source, Function<String, String> transformer) {

213

this.source = source;

214

this.transformer = transformer;

215

}

216

217

@Override

218

public InputStream openStream() {

219

try (Scanner scanner = new Scanner(source.openStream())) {

220

String content = scanner.useDelimiter("\\A").next();

221

String transformed = transformer.apply(content);

222

return new ByteArrayInputStream(transformed.getBytes());

223

}

224

}

225

}

226

227

// Usage: Replace placeholders in configuration files

228

Asset template = new ClassLoaderAsset("config-template.xml");

229

Asset configured = new TransformingAsset(template, content ->

230

content.replace("${app.name}", "MyApplication")

231

.replace("${app.version}", "1.0.0"));

232

archive.addAsResource(configured, "config.xml");

233

```

234

235

## Service Provider Management

236

237

### Advanced Service Provider Configuration

238

239

Creating complex service provider configurations:

240

241

```java

242

public class AdvancedServiceProviderAsset implements Asset {

243

private final Map<String, List<String>> serviceProviders;

244

245

public AdvancedServiceProviderAsset() {

246

this.serviceProviders = new HashMap<>();

247

}

248

249

public AdvancedServiceProviderAsset addProvider(Class<?> service, Class<?>... implementations) {

250

String serviceName = service.getName();

251

List<String> impls = Arrays.stream(implementations)

252

.map(Class::getName)

253

.collect(Collectors.toList());

254

serviceProviders.put(serviceName, impls);

255

return this;

256

}

257

258

public void addToArchive(Archive<?> archive) {

259

serviceProviders.forEach((service, implementations) -> {

260

ServiceProviderAsset asset = new ServiceProviderAsset(

261

implementations.toArray(new String[0])

262

);

263

archive.addAsManifestResource(asset, "services/" + service);

264

});

265

}

266

}

267

268

// Usage: Configure multiple services

269

AdvancedServiceProviderAsset serviceConfig = new AdvancedServiceProviderAsset()

270

.addProvider(DatabaseService.class, MySQLService.class, PostgreSQLService.class)

271

.addProvider(CacheService.class, RedisService.class, MemcachedService.class)

272

.addProvider(LoggingService.class, Log4jService.class);

273

274

serviceConfig.addToArchive(archive);

275

```

276

277

### Service Provider Discovery

278

279

Utilities for discovering existing service providers:

280

281

```java

282

public class ServiceProviderDiscovery {

283

public static Set<String> discoverProviders(Class<?> serviceClass, ClassLoader classLoader) {

284

ServiceLoader<?> loader = ServiceLoader.load(serviceClass, classLoader);

285

return StreamSupport.stream(loader.spliterator(), false)

286

.map(provider -> provider.getClass().getName())

287

.collect(Collectors.toSet());

288

}

289

290

public static ServiceProviderAsset createFromDiscovered(Class<?> serviceClass) {

291

Set<String> providers = discoverProviders(serviceClass,

292

Thread.currentThread().getContextClassLoader());

293

return new ServiceProviderAsset(providers.toArray(new String[0]));

294

}

295

}

296

297

// Usage: Auto-discover and configure services

298

ServiceProviderAsset auto = ServiceProviderDiscovery.createFromDiscovered(Plugin.class);

299

archive.addAsManifestResource(auto, "services/com.example.Plugin");

300

```

301

302

## Asset Validation

303

304

### Content Validation

305

306

Validating asset content before inclusion:

307

308

```java

309

public class ValidatingAsset implements Asset {

310

private final Asset delegate;

311

private final Predicate<byte[]> validator;

312

313

public ValidatingAsset(Asset delegate, Predicate<byte[]> validator) {

314

this.delegate = delegate;

315

this.validator = validator;

316

}

317

318

@Override

319

public InputStream openStream() {

320

byte[] content = IOUtilDelegator.asByteArray(delegate.openStream());

321

322

if (!validator.test(content)) {

323

throw new IllegalStateException("Asset content validation failed");

324

}

325

326

return new ByteArrayInputStream(content);

327

}

328

}

329

330

// Usage: Validate XML content

331

Predicate<byte[]> xmlValidator = content -> {

332

try {

333

DocumentBuilder builder = DocumentBuilderFactory.newInstance()

334

.newDocumentBuilder();

335

builder.parse(new ByteArrayInputStream(content));

336

return true;

337

} catch (Exception e) {

338

return false;

339

}

340

};

341

342

Asset xmlAsset = new ValidatingAsset(

343

new FileAsset("config.xml"),

344

xmlValidator

345

);

346

```

347

348

## Performance Considerations

349

350

### Lazy Loading

351

352

Assets support lazy loading to minimize memory usage:

353

354

```java

355

// Assets are loaded on-demand

356

Asset asset = new FileAsset("large-file.dat");

357

archive.add(asset, "/data/large-file.dat");

358

359

// Content is not loaded until openStream() is called

360

InputStream stream = archive.get("/data/large-file.dat")

361

.getAsset()

362

.openStream();

363

```

364

365

### Memory Management

366

367

Efficient memory usage with streaming operations:

368

369

```java

370

// Stream large assets without loading entirely into memory

371

public static void copyLargeAsset(Asset source, OutputStream target) {

372

try (InputStream input = source.openStream()) {

373

IOUtilDelegator.copy(input, target);

374

}

375

}

376

```

377

378

### Asset Caching

379

380

Caching for frequently accessed assets:

381

382

```java

383

public class CachedAsset implements Asset {

384

private final Asset delegate;

385

private byte[] cachedContent;

386

387

public CachedAsset(Asset delegate) {

388

this.delegate = delegate;

389

}

390

391

@Override

392

public synchronized InputStream openStream() {

393

if (cachedContent == null) {

394

cachedContent = IOUtilDelegator.asByteArray(delegate.openStream());

395

}

396

return new ByteArrayInputStream(cachedContent);

397

}

398

}

399

```