Tuesday, February 10, 2009

Convert a jar to an optional package

Here's the code I promised I would post to convert a jar pulled out of a Maven repository into an optional package. Note here that jars pulled out of a Maven repository have the following example syntax: examplelib-1.0.0.jar. Given this syntax, the following code manipulates the Manifest of the jar to make the jar compatible with the JEE optional package specifications:

ZipFile oldZipFile = new ZipFile(new File(fileName));
Enumeration entries = oldZipFile.entries();

ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
outFile));

// Loop through entries in the existing jar file
while (entries.hasMoreElements())
{
ZipEntry entry = entries.nextElement();
// Put all other files besides the manifest into the converted jar as is
if (entry.getName().indexOf("MANIFEST") == -1)
{
out.putNextEntry(entry);

InputStream inStream = oldZipFile.getInputStream(entry);
// Transfer bytes from the ZIP file to the output file
byte[] buf = new byte[1024];
int len;
while ((len = inStream.read(buf)) > 0)
out.write(buf, 0, len);

inStream.close();
}
else
{
manifest = new OptManifest();
manifest.setExtName(trueFileName);

// Read the manifest
InputStream inStream = oldZipFile.getInputStream(entry);
BufferedReader in = new BufferedReader(
new InputStreamReader(inStream));
StringBuffer buffer = new StringBuffer();

// Read each line of the manifest file to determine its state
boolean extnNameFound = false;
boolean specVerFound = false;
boolean implVerFound = false;

String line = null;
while ((line = in.readLine()) != null)
{
if ( !specVerFound )
specVerFound = ( line.toLowerCase().indexOf("specification-version")!=-1? true: false );

if ( !implVerFound )
implVerFound = ( line.toLowerCase().indexOf("implementation-version")!=-1? true: false );

if ( !extnNameFound )
extnNameFound = (line.toLowerCase().indexOf("extension-name")!=-1? true: false);

boolean hasOptPkgParam = ( specVerFound || implVerFound || extnNameFound? true : false );

// Add lines that are not optional package parameters
if ( line!=null && !line.equals("") && !hasOptPkgParam )
buffer.append(line + "\n");
}

// Add Optional package information to the manifest
String versionToUse = determineVersion(fileName);
if ( versionToUse!=null && !versionToUse.equals("") )
{
// Assign cleaned up specification version
String specVersionToUse = getSpecificationVersion(versionToUse);
buffer.append("Specification-Version: " + specVersionToUse + "\n");
manifest.setExtSpecVersion(specVersionToUse);

// Assign cleaned up implementation version
String implVersionToUse = getImplementationVersion(versionToUse);
buffer.append("Implementation-Version: " + implVersionToUse + "\n");
manifest.setExtImplVersion(implVersionToUse);
}

inStream.close();
in.close();

ZipEntry newManifestEntry = new ZipEntry(entry.getName());
out.putNextEntry(newManifestEntry);

// Transfer bytes from the file to the ZIP file
out.write(buffer.toString().getBytes());
}

// Close the new entry in the new zip file
out.closeEntry();
}
out.close();


Here's how your can derive the specification and implementation versions:

private String getSpecificationVersion(String versionToUse)
{
StringBuffer specVersionToUse = new StringBuffer();
// Regex expression that only allows digits and periods, and a digit cannot
// be preceded by an underscore
String regex = "(?<!_| )[\\.?[0-9]*]";
Pattern pattern = Pattern.compile(regex);
Matcher m = pattern.matcher(versionToUse);
while ( m.find() )
specVersionToUse.append(m.group());

if ( specVersionToUse.charAt(0)=='.')
specVersionToUse = specVersionToUse.replace(0, 1, "");

if ( specVersionToUse.charAt(specVersionToUse.length()-1)=='.')
specVersionToUse = specVersionToUse.replace(specVersionToUse.length()-1, specVersionToUse.length(), "");

return specVersionToUse.toString();
}

private String getImplementationVersion(String versionToUse)
{
String implVersion = versionToUse;
int versionIndex = versionToUse.indexOf('-');

// Get the version starting from the hyphen prior to a digit
String regexPattern = "[0-9]";
while ( versionIndex!=-1 )
{
char charAtIndex = versionToUse.charAt(versionIndex+1);
if ( !Pattern.matches(regexPattern, String.valueOf(charAtIndex)) )
versionIndex = versionToUse.indexOf('-', versionIndex+1);
else
{
implVersion = versionToUse.substring(versionIndex+1);
break;
}
}
return implVersion;
}

No comments: