blob: c0f4623d0f9ae4a6e85a51b4c4d6f24f97d388e8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2006 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
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.j2ee.commonarchivecore.internal.helpers;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
import com.ibm.icu.util.StringTokenizer;
import java.util.jar.Attributes;
import org.eclipse.jst.j2ee.commonarchivecore.internal.util.ArchiveUtil;
/**
* Helper class for manifest files
*/
public class ArchiveManifestImpl extends java.util.jar.Manifest implements org.eclipse.jst.j2ee.commonarchivecore.internal.helpers.ArchiveManifest {
/**
* ArchiveManifest constructor comment.
*/
public ArchiveManifestImpl() {
super();
}
/**
* ArchiveManifest constructor comment.
*
* @param is
* java.io.InputStream
* @throws java.io.IOException
* The exception description.
*/
public ArchiveManifestImpl(java.io.InputStream is) throws java.io.IOException {
super(is);
}
/**
* ArchiveManifest constructor comment.
*
* @param man
* java.util.jar.Manifest
*/
public ArchiveManifestImpl(java.util.jar.Manifest man) {
super(man);
}
/**
* Creates a new manifest entry (attributes) for the given name
*/
public void addEntry(String entryName) {
Attributes attr = new Attributes();
addEntry(entryName, attr);
}
public void addEntry(String entryName, Attributes attr) {
getEntries().put(entryName, attr);
}
/**
* Adds the key/value pair to the attributes for the given entry name; if the entry does not
* exist, creates a new attributes
*/
public void addEntryAttribute(String entryName, String key, String value) {
Attributes attr = getAttributes(entryName);
if (attr == null)
addEntry(entryName);
attr = getAttributes(entryName);
attr.putValue(key, value);
}
public void addVersionIfNecessary() {
//This is a hack because of the fact that the manifest does not serialize correctly if
//The version is not set. In addition to saves, the serialization is used for copy
if (getManifestVersion() == null || getManifestVersion().equals(""))//$NON-NLS-1$
setManifestVersion("1.0");//$NON-NLS-1$
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public void appendClassPath(java.lang.String extension) {
String classPath = getClassPath();
if (classPath != null)
setClassPath(classPath + " " + extension);//$NON-NLS-1$
else
setClassPath(extension);
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public java.lang.String getClassPath() {
return ArchiveUtil.getValueIgnoreKeyCase(Attributes.Name.CLASS_PATH.toString(), getMainAttributes());
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public java.lang.String[] getClassPathTokenized() {
String classPath = getClassPath();
if (classPath == null)
return new String[0];
return org.eclipse.jst.j2ee.commonarchivecore.internal.util.ArchiveUtil.getTokens(classPath);
}
public String getEntryAttribute(String entryName, String key) {
Attributes attr = getAttributes(entryName);
if (attr == null)
return null;
return attr.getValue(key);
}
public String getMainClass() {
return ArchiveUtil.getValueIgnoreKeyCase(Attributes.Name.MAIN_CLASS.toString(), getMainAttributes());
}
public String getManifestVersion() {
return getMainAttributes().getValue(Attributes.Name.MANIFEST_VERSION);
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public void mergeClassPath(java.lang.String[] classPathEntries) {
StringBuffer sb = new StringBuffer();
java.util.List existing = java.util.Arrays.asList(getClassPathTokenized());
String cp = getClassPath();
if (cp != null)
sb.append(cp);
boolean empty = cp == null || "".equals(cp); //$NON-NLS-1$
for (int i = 0; i < classPathEntries.length; i++) {
if (!existing.contains(classPathEntries[i])) {
if (!empty)
sb.append(" "); //$NON-NLS-1$
else
empty = false;
sb.append(classPathEntries[i]);
}
}
setClassPath(sb.toString());
}
public void removeEntry(String entryName) {
getEntries().remove(entryName);
}
public void removeEntryAttribute(String entryName, Object key) {
Attributes attr = getAttributes(entryName);
if (attr != null)
attr.remove(key);
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public void setClassPath(java.lang.String aSpaceDelimitedPath) {
Attributes attributes = getMainAttributes();
if (aSpaceDelimitedPath == null)
attributes.remove(Attributes.Name.CLASS_PATH);
else
attributes.putValue(Attributes.Name.CLASS_PATH.toString(), aSpaceDelimitedPath);
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public void setMainClass(java.lang.String className) {
Attributes attributes = getMainAttributes();
if (className == null)
attributes.remove(Attributes.Name.MAIN_CLASS);
else
attributes.putValue(Attributes.Name.MAIN_CLASS.toString(), className);
}
/**
* @see com.ibm.etools.archive.ArchiveManifest
*/
public void setManifestVersion(java.lang.String version) {
Attributes attributes = getMainAttributes();
attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), version);
}
/**
* Writes the Manifest to the specified OutputStream, splitting each classpath entry on a line
* by itself.
*
* @param out
* the output stream
* @exception IOException
* if an I/O error has occurred
*/
public void writeSplittingClasspath(OutputStream out) throws IOException {
DataOutputStream dos = new DataOutputStream(out);
// Write out the main attributes for the manifest
writeMainSplittingClasspath(getMainAttributes(), dos);
// Now write out the pre-entry attributes
Iterator it = getEntries().entrySet().iterator();
while (it.hasNext()) {
Map.Entry e = (Map.Entry) it.next();
StringBuffer buffer = new StringBuffer("Name: "); //$NON-NLS-1$
buffer.append((String) e.getKey());
buffer.append("\r\n"); //$NON-NLS-1$
localMake72Safe(buffer);
dos.writeBytes(buffer.toString());
write((Attributes) e.getValue(), dos);
}
dos.flush();
}
/*
* Writes the current attributes to the specified data output stream. XXX Need to handle UTF8
* values and break up lines longer than 72 bytes
*
* @see Attributes#write
*/
protected void write(Attributes attributes, DataOutputStream os) throws IOException {
Iterator it = attributes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry e = (Map.Entry) it.next();
StringBuffer buffer = new StringBuffer(((Attributes.Name) e.getKey()).toString());
buffer.append(": "); //$NON-NLS-1$
buffer.append(toUtf8((String) e.getValue()));
buffer.append("\r\n"); //$NON-NLS-1$
localMake72Safe(buffer);
os.writeBytes(buffer.toString());
}
os.writeBytes("\r\n"); //$NON-NLS-1$
}
/*
* Writes the current attributes to the specified data output stream, make sure to write out the
* MANIFEST_VERSION or SIGNATURE_VERSION attributes first.
*
* @see Attributes#writeMain
*/
protected void writeMainSplittingClasspath(Attributes attributes, DataOutputStream out) throws IOException {
// write out the *-Version header first, if it exists
String vername = Attributes.Name.MANIFEST_VERSION.toString();
String version = toUtf8(attributes.getValue(vername));
if (version == null) {
vername = Attributes.Name.SIGNATURE_VERSION.toString();
version = toUtf8(attributes.getValue(vername));
}
if (version != null) {
out.writeBytes(vername + ": " + version + "\r\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
// write out all attributes except for the version
// we wrote out earlier
Iterator it = attributes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry e = (Map.Entry) it.next();
String name = ((Attributes.Name) e.getKey()).toString();
if ((version != null) && !(name.equalsIgnoreCase(vername))) {
if (name.equalsIgnoreCase(Attributes.Name.CLASS_PATH.toString())) {
writeSplit(out, name, toUtf8((String) e.getValue()));
continue;
}
StringBuffer buffer = new StringBuffer(name);
buffer.append(": "); //$NON-NLS-1$
buffer.append(toUtf8((String) e.getValue()));
buffer.append("\r\n"); //$NON-NLS-1$
localMake72Safe(buffer);
out.writeBytes(buffer.toString());
}
}
out.writeBytes("\r\n"); //$NON-NLS-1$
}
protected void writeSplit(DataOutputStream out, String name, String value) throws IOException {
StringTokenizer tok = new StringTokenizer(value);
int inc = 0;
while (tok.hasMoreTokens()) {
StringBuffer buffer = null;
if (inc == 0) {
buffer = new StringBuffer(name);
buffer.append(": "); //$NON-NLS-1$
} else {
buffer = new StringBuffer();
buffer.append(' ');
}
buffer.append(tok.nextToken());
if (tok.countTokens() > 0)
buffer.append(" \r\n"); //$NON-NLS-1$
else
buffer.append("\r\n"); //$NON-NLS-1$
localMake72Safe(buffer);
out.writeBytes(buffer.toString());
inc++;
}
}
/**
* Adds line breaks to enforce a maximum 72 bytes per line.
*/
protected static void localMake72Safe(StringBuffer line) {
int length = line.length();
if (length > 72) {
int index = 70;
while (index - 1 < length) {
line.insert(index, "\r\n "); //$NON-NLS-1$
index += 72;
length += 3;
}
}
return;
}
public String getImplementationVersion() {
return getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
}
public void setImplemenationVersion(String version) {
Attributes attributes = getMainAttributes();
attributes.putValue(Attributes.Name.IMPLEMENTATION_VERSION.toString(), version);
}
/**
* Encodes a double-byte string into UTF8 form. Every character in the
* returned string represents one byte of the UTF8 encoding.
*/
private String toUtf8( final String str ) throws IOException
{
if( str == null )
{
return null;
}
else
{
final byte[] utf8 = str.getBytes( "UTF-8" );
return new String( utf8, 0, 0, utf8.length );
}
}
}