/*
* #%L
* Gravia :: Resource
* %%
* Copyright (C) 2010 - 2014 JBoss by Red Hat
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.jboss.gravia.resource;
import static org.jboss.gravia.resource.spi.ResourceLogger.LOGGER;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.jboss.gravia.Constants;
/**
* A simple manifest builder.
*
* @author thomas.diesler@jboss.com
* @since 08-Mar-2010
*/
public final class ManifestBuilder {
public enum Type {
String,
Version,
VersionRange,
Long,
Double
}
private final Map<String, String> identityRequirements = new LinkedHashMap<String, String>();
private final List<String> genericCapabilities = new ArrayList<String>();
private final List<String> genericRequirements = new ArrayList<String>();
private List<String> lines = new ArrayList<String>();
private Manifest manifest;
public ManifestBuilder() {
this("1.0");
}
public ManifestBuilder(String manifestVersion) {
if (manifestVersion != null) {
append(Attributes.Name.MANIFEST_VERSION + ": " + manifestVersion);
}
}
public ManifestBuilder addIdentityCapability(ResourceIdentity identity) {
return addIdentityCapability(identity.getSymbolicName(), identity.getVersion());
}
public ManifestBuilder addIdentityCapability(String symbolicName, String version) {
return addIdentityCapability(symbolicName, Version.parseVersion(version), null, null);
}
public ManifestBuilder addIdentityCapability(String symbolicName, Version version) {
return addIdentityCapability(symbolicName, version, null, null);
}
public ManifestBuilder addIdentityCapability(String symbolicName, Version version, Map<String, String> atts, Map<String, String> dirs) {
StringBuffer buffer = new StringBuffer(symbolicName);
if (version != null) {
buffer.append(";version=\"" + version + "\"");
}
if (atts != null) {
for (Entry<String, String> entry : atts.entrySet()) {
buffer.append(";" + entry.getKey() + "=\"" + entry.getValue() + "\"");
}
}
if (dirs != null) {
for (Entry<String, String> entry : dirs.entrySet()) {
buffer.append(";" + entry.getKey() + ":=\"" + entry.getValue() + "\"");
}
}
addManifestHeader(Constants.GRAVIA_IDENTITY_CAPABILITY, buffer.toString());
return this;
}
public ManifestBuilder addIdentityRequirement(String symbolicName, String version) {
return addIdentityRequirement(symbolicName, new VersionRange(version), null, null);
}
public ManifestBuilder addIdentityRequirement(String symbolicName, VersionRange version) {
return addIdentityRequirement(symbolicName, version, null, null);
}
public ManifestBuilder addIdentityRequirement(String symbolicName, VersionRange version, Map<String, String> atts, Map<String, String> dirs) {
StringBuffer buffer = new StringBuffer(symbolicName);
if (version != null) {
buffer.append(";version=\"" + version + "\"");
}
if (atts != null) {
for (Entry<String, String> entry : atts.entrySet()) {
buffer.append(";" + entry.getKey() + "=\"" + entry.getValue() + "\"");
}
}
if (dirs != null) {
for (Entry<String, String> entry : dirs.entrySet()) {
buffer.append(";" + entry.getKey() + ":=\"" + entry.getValue() + "\"");
}
}
addEntry(identityRequirements, buffer.toString());
return this;
}
public ManifestBuilder addManifestHeader(String key, String value) {
append(key + ": " + value);
return this;
}
public ManifestBuilder addModuleActivator(String className) {
addManifestHeader(Constants.MODULE_ACTIVATOR, className);
return this;
}
public ManifestBuilder addModuleActivator(Class<?> clazz) {
addManifestHeader(Constants.MODULE_ACTIVATOR, clazz.getName());
return this;
}
public ManifestBuilder addGenericCapabilities(String... capabilities) {
for (String entry : capabilities) {
genericCapabilities.add(entry);
}
return this;
}
public ManifestBuilder addGenericCapability(String namespace, Map<String, String> atts, Map<String, String> dirs) {
genericCapabilities.add(getCapabilitySpec(namespace, atts, dirs));
return this;
}
public ManifestBuilder addGenericRequirements(String... capabilities) {
for (String entry : capabilities) {
genericRequirements.add(entry);
}
return this;
}
public ManifestBuilder addGenericRequirement(String namespace, Map<String, String> atts, Map<String, String> dirs) {
genericRequirements.add(getCapabilitySpec(namespace, atts, dirs));
return this;
}
private String getCapabilitySpec(String namespace, Map<String, String> atts, Map<String, String> dirs) {
StringBuffer buffer = new StringBuffer(namespace);
if (atts != null) {
for (Entry<String, String> entry : atts.entrySet()) {
buffer.append(";" + entry.getKey() + "=\"" + entry.getValue() + "\"");
}
}
if (dirs != null) {
for (Entry<String, String> entry : dirs.entrySet()) {
buffer.append(";" + entry.getKey() + ":=\"" + entry.getValue() + "\"");
}
}
return buffer.toString();
}
// Strip attributes/directives to avoid duplicates
private void addEntry(Map<String, String> target, String entry) {
String key = entry;
int index = entry.indexOf(";");
if (index > 0) {
key = entry.substring(0, index);
}
if (target.get(key) == null) {
target.put(key, entry);
} else {
LOGGER.warn("Ignore duplicate entery: {}", entry);
}
}
/**
* Validate a given manifest.
*
* @param manifest The given manifest
* @return True if the manifest is valid
*/
public static boolean isValidManifest(Manifest manifest) {
if (manifest == null)
return false;
try {
validateManifest(manifest);
return true;
} catch (RuntimeException e) {
return false;
}
}
/**
* Validate a given manifest.
*
* @param manifest The given manifest
* @throws IllegalArgumentException if the given manifest is not a valid Gravia manifest
*/
public static void validateManifest(Manifest manifest) {
if (manifest == null)
throw new IllegalArgumentException("Null manifest");
String identitySpec = getManifestHeaderInternal(manifest, Constants.GRAVIA_IDENTITY_CAPABILITY);
if (identitySpec == null)
throw new IllegalArgumentException("Cannot obtain required header: " + Constants.GRAVIA_IDENTITY_CAPABILITY);
}
private static String getManifestHeaderInternal(Manifest manifest, String key) {
Attributes attribs = manifest.getMainAttributes();
String value = attribs.getValue(key);
return value != null ? value.trim() : null;
}
public Manifest getManifest() {
if (manifest == null) {
addManifestHeader(Constants.GRAVIA_IDENTITY_REQUIREMENT, identityRequirements);
addManifestHeader(Constants.GRAVIA_CAPABILITY, genericCapabilities);
addManifestHeader(Constants.GRAVIA_REQUIREMENT, genericRequirements);
StringWriter out = new StringWriter();
PrintWriter pw = new PrintWriter(out);
for(String line : lines) {
byte[] bytes = line.getBytes();
while (bytes.length >= 512) {
byte[] head = Arrays.copyOf(bytes, 256);
bytes = Arrays.copyOfRange(bytes, 256, bytes.length);
pw.println(new String(head));
pw.print(" ");
}
pw.println(new String(bytes));
}
String content = out.toString();
if (LOGGER.isTraceEnabled())
LOGGER.trace(content);
try {
manifest = new Manifest(new ByteArrayInputStream(content.getBytes()));
} catch (IOException ex) {
throw new IllegalStateException("Cannot create manifest", ex);
}
}
return manifest;
}
private void addManifestHeader(String header, Map<String, String> source) {
if (source.size() > 0) {
int i = 0;
StringBuffer buffer = new StringBuffer();
for (String entry : source.values()) {
buffer.append(i++ > 0 ? "," : "");
buffer.append(entry);
}
addManifestHeader(header, buffer.toString());
}
}
private void addManifestHeader(String header, List<String> source) {
if (source.size() > 0) {
int i = 0;
StringBuffer buffer = new StringBuffer();
for (String entry : source) {
buffer.append(i++ > 0 ? "," : "");
buffer.append(entry);
}
addManifestHeader(header, buffer.toString());
}
}
public InputStream openStream() {
Manifest manifest = getManifest();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
manifest.write(baos);
return new ByteArrayInputStream(baos.toByteArray());
} catch (IOException ex) {
throw new IllegalStateException("Cannot provide manifest input stream", ex);
}
}
public void append(String line) {
if (manifest != null)
throw new IllegalStateException("Cannot append to existing manifest");
lines.add(line);
}
}