/*******************************************************************************
* Copyright (c) 2014 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Jochen Hiller
*******************************************************************************/
package org.eclipse.concierge.test.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import org.osgi.framework.Constants;
/**
* This class will support to create synthetic bundles. It will provide a fluent
* interface.
*/
public class SyntheticBundleBuilder {
private final Map<Attributes.Name, String> manifestHeaders;
private final Map<String, File> files;
private final Map<String, String> content;
public static SyntheticBundleBuilder newBuilder() {
return new SyntheticBundleBuilder();
}
public SyntheticBundleBuilder() {
// preserve files and added content
this.files = new HashMap<String, File>();
this.content = new HashMap<String, String>();
// pre-fill default headers
final Map<Attributes.Name, String> headers = new HashMap<Attributes.Name, String>();
headers.put(Attributes.Name.MANIFEST_VERSION, "1.0");
headers.put(new Attributes.Name(Constants.BUNDLE_MANIFESTVERSION), "2");
headers.put(new Attributes.Name(Constants.BUNDLE_VERSION), "0.0.0");
this.manifestHeaders = headers;
}
public SyntheticBundleBuilder bundleSymbolicName(final String bsn) {
this.manifestHeaders.put(new Attributes.Name(
Constants.BUNDLE_SYMBOLICNAME), bsn);
return this;
}
public SyntheticBundleBuilder singleton() {
String bsn = this.manifestHeaders.get(new Attributes.Name(
Constants.BUNDLE_SYMBOLICNAME));
bsn = bsn + ";singleton:=true";
this.manifestHeaders.put(new Attributes.Name(
Constants.BUNDLE_SYMBOLICNAME), bsn);
return this;
}
public SyntheticBundleBuilder bundleVersion(final String version) {
this.manifestHeaders.put(new Attributes.Name(Constants.BUNDLE_VERSION),
version);
return this;
}
public String getBundleSymbolicName() {
return this.manifestHeaders.get(new Attributes.Name(
Constants.BUNDLE_SYMBOLICNAME));
}
public String getBundleVersion() {
final String version = this.manifestHeaders.get(new Attributes.Name(
Constants.BUNDLE_VERSION));
return version;
}
public SyntheticBundleBuilder addManifestHeader(final String key,
final String value) {
// add the header into Manifest
this.manifestHeaders.put(new Attributes.Name(key), value);
return this;
}
public SyntheticBundleBuilder addManifestHeaders(
final Map<String, String> headers) {
// add the headers into Manifest
for (Iterator<Map.Entry<String, String>> iter = headers.entrySet()
.iterator(); iter.hasNext();) {
final Map.Entry<String, String> entry = iter.next();
this.manifestHeaders.put(new Attributes.Name(entry.getKey()),
entry.getValue());
}
return this;
}
/**
* Use addFile() for binary content.
*/
public SyntheticBundleBuilder addFile(final String resPath, final File file) {
this.files.put(resPath, file);
return this;
}
/**
* Use addFile() for simple text content.
*/
public SyntheticBundleBuilder addFile(final String resPath,
final String content) {
this.content.put(resPath, content);
return this;
}
public InputStream asInputStream() {
// copy MANIFEST to a jar file in memory
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final Manifest manifest = new Manifest();
for (Iterator<Map.Entry<Attributes.Name, String>> iter = this.manifestHeaders
.entrySet().iterator(); iter.hasNext();) {
final Map.Entry<Attributes.Name, String> entry = iter.next();
manifest.getMainAttributes().put(entry.getKey(), entry.getValue());
}
JarOutputStream jarStream = null;
try {
jarStream = new JarOutputStream(out, manifest);
// copy files into JAR
for (Iterator<Map.Entry<String, File>> iter = this.files.entrySet()
.iterator(); iter.hasNext();) {
final Map.Entry<String, File> entry = iter.next();
final String resPath = entry.getKey();
final File f = entry.getValue();
final FileInputStream fis = new FileInputStream(f);
final JarEntry je = new JarEntry(resPath);
jarStream.putNextEntry(je);
TestUtils.copyStream(fis, jarStream);
jarStream.closeEntry();
fis.close();
}
// copy content into JAR
for (Iterator<Map.Entry<String, String>> iter = this.content
.entrySet().iterator(); iter.hasNext();) {
final Map.Entry<String, String> entry = iter.next();
final String resPath = entry.getKey();
final String s = entry.getValue();
final InputStream stringInputStream = new ByteArrayInputStream(
s.getBytes(Charset.forName("UTF-8")));
final JarEntry je = new JarEntry(resPath);
jarStream.putNextEntry(je);
TestUtils.copyStream(stringInputStream, jarStream);
jarStream.closeEntry();
stringInputStream.close();
}
jarStream.close();
final InputStream is = new ByteArrayInputStream(out.toByteArray());
return is;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (jarStream != null) {
try {
jarStream.close();
} catch (IOException e) {
// ignore
}
}
}
}
public File asFile() {
File destFile = new File("concierge-" + this.getBundleSymbolicName()
+ "-" + getBundleVersion() + ".jar");
String destFileName = destFile.getAbsolutePath();
File createdDestFile = asFile(destFileName);
return createdDestFile;
}
public File asFile(String destFileName) {
final InputStream is = this.asInputStream();
try {
File destFile = new File(destFileName);
// ensure parent dir will be created
new File(destFile.getParent()).mkdirs();
TestUtils.copyStreamToFile(is, destFile);
return destFile;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}