/*
* Copyright 2011 cruxframework.org.
*
* 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.
*/
package org.cruxframework.crux.tools.jar;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import org.cruxframework.crux.core.client.Legacy;
import org.cruxframework.crux.core.client.utils.StringUtils;
import org.cruxframework.crux.core.utils.FilePatternHandler;
import org.cruxframework.crux.core.utils.FileUtils;
/**
* A Helper class to create Jar files.
* @author Thiago da Rosa de Bustamante
*
*/
@Deprecated
@Legacy
public class JarCreator extends FilePatternHandler
{
public static final String MANIFEST_BUILD_TIMESTAMP_PROPERTY = "Build-Timestamp";
private static DateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
private Map<String, String> metaInfAttributes;
private final File[] inputDirectory;
private final File outputFile;
private final boolean unpackaged;
/**
* @param inputDirectory
* @param outputFile
* @throws IOException
*/
public JarCreator(File[] inputDirectory, File outputFile) throws IOException
{
this(inputDirectory, outputFile, new HashMap<String, String>());
}
/**
* @param inputDirectory
* @param outputFile
* @param metaInfAttributes
* @throws IOException
*/
public JarCreator(File[] inputDirectory, File outputFile, Map<String, String> metaInfAttributes) throws IOException
{
this(inputDirectory, outputFile, null, null, metaInfAttributes, false);
}
/**
* @param inputDirectory
* @param outputFile
* @param includes
* @param excludes
* @param metaInfAttributes
* @throws IOException
*/
public JarCreator(File[] inputDirectory, File outputFile, String includes, String excludes, Map<String, String> metaInfAttributes, boolean unpackaged) throws IOException
{
super(includes, excludes);
this.inputDirectory = inputDirectory;
this.outputFile = outputFile;
this.metaInfAttributes = metaInfAttributes;
this.unpackaged = unpackaged;
}
/**
* @throws IOException
*/
public void createJar() throws IOException
{
Manifest manifest = new Manifest();
setDefaultAttributes(metaInfAttributes);
for (String attrName : metaInfAttributes.keySet())
{
manifest.getMainAttributes().putValue(attrName, metaInfAttributes.get(attrName));
}
removeOldJar();
if (unpackaged)
{
for (File inputDir : inputDirectory)
{
FileUtils.copyFilesFromDir(inputDir, outputFile, getIncludes(), getExcludes());
}
File metaInfDir = new File(outputFile, "META-INF");
metaInfDir.mkdirs();
manifest.write(new FileOutputStream(new File(metaInfDir, "MANIFEST.MF")));
}
else
{
File parentFile = outputFile.getParentFile();
if (parentFile != null && !parentFile.exists())
{
parentFile.mkdirs();
}
JarOutputStream target = new JarOutputStream(new FileOutputStream(outputFile), manifest);
if (inputDirectory != null)
{
Set<String> added = new HashSet<String>();
for (File inputDir : inputDirectory)
{
addFile(inputDir, target, inputDir.getCanonicalPath().length(), added);
}
}
target.close();
}
}
/**
* Removes the old generated jar if it exists.
* @throws IOException
*/
private void removeOldJar() throws IOException
{
if(outputFile.exists())
{
if(outputFile.isDirectory())
{
if(!FileUtils.recursiveDelete(outputFile))
{
throw new IOException("Could not delete file [" + outputFile.getAbsolutePath() + "]");
}
}
else
{
if(!outputFile.delete())
{
throw new IOException("Could not delete file [" + outputFile.getAbsolutePath() + "]");
}
}
}
}
/**
* @param source
* @param target
* @param inputDirNameLength
* @param added
* @throws IOException
*/
private void addFile(File source, JarOutputStream target, int inputDirNameLength, Set<String> added) throws IOException
{
BufferedInputStream in = null;
try
{
String entryName = getEntryName(source, inputDirNameLength);
if (source.isDirectory())
{
String name = entryName;
if (!StringUtils.isEmpty(name) && !added.contains(name))
{
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
added.add(name);
}
for (File nestedFile : source.listFiles())
{
addFile(nestedFile, target, inputDirNameLength, added);
}
return;
}
if (isValidEntry(entryName) && !added.contains(entryName))
{
JarEntry entry = new JarEntry(entryName);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
{
break;
}
target.write(buffer, 0, count);
}
target.closeEntry();
added.add(entryName);
}
}
finally
{
if (in != null)
{
in.close();
}
}
}
/**
* @param source
* @param inputDirNameLength
* @return
* @throws IOException
*/
private String getEntryName(File source, int inputDirNameLength) throws IOException
{
String name = source.getCanonicalPath().substring(inputDirNameLength).replace("\\", "/");
if (name.startsWith("/"))
{
name = name.substring(1);
}
if (source.isDirectory() && !name.endsWith("/"))
{
name += "/";
}
return name;
}
/**
* Sets the default attributes to manifest. If one of those attributes already exists on
* metaInfAttributes map, it will be replaced.
* @param metaInfAttributes
*/
private void setDefaultAttributes(Map<String, String> metaInfAttributes)
{
metaInfAttributes.put(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
metaInfAttributes.put(MANIFEST_BUILD_TIMESTAMP_PROPERTY, dateFormatter.format(new Date()));
}
}