package org.codehaus.mojo.jsimport;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.Artifact;
/**
* Processes an artifact and makes available one or more files depending on whether the artifact points to a js file or
* a "-www.zip" file respectively.
*
* @author Christopher Hunt
*/
public class JsFileArtifactHandler
{
private List<File> files = new ArrayList<File>();;
private File expansionFolder;
/**
* @param artifact the artifact to work with. It can either be for a JS file or a zip file with a classifier of
* "www".
* @param targetFolder the folder to merge non js files into.
* @param workFolder the folder to store any meta data that will help us do things like avoiding unnecessary unzips
* (given that it has been done before etc.).
* @throws IOException if something goes wrong, particularly in the course of zip file expansion.
*/
public JsFileArtifactHandler( Artifact artifact, File targetFolder, File workFolder )
throws IOException
{
if ( artifact.getType().equals( "js" ) )
{
files = new ArrayList<File>( 1 );
files.add( artifact.getFile() );
}
else
{
assert artifact.getType().equals( "zip" ) && artifact.getClassifier().equals( "www" );
File wwwZipFile = artifact.getFile();
files = expandWwwZipIntoTargetFolder( artifact, wwwZipFile, targetFolder, workFolder );
}
}
private List<File> expandWwwZipIntoTargetFolder( Artifact artifact, File wwwZipFile, File targetFolder,
File workFolder )
throws IOException
{
List<File> jsFiles = new ArrayList<File>();
// FIXME: Need to consider scope here i.e. don't create a compile www-zip file for a test run.
expansionFolder = new File( workFolder, "www-zip" + File.separator + wwwZipFile.getName() );
// Don't expand if it is already expanded.
if ( wwwZipFile.lastModified() > expansionFolder.lastModified() )
{
String gavPath =
artifact.getGroupId().replace( '.', File.separatorChar ) + File.separator + artifact.getArtifactId()
+ File.separator + artifact.getVersion();
File jsExpansionFolder = new File( expansionFolder, gavPath );
FileInputStream fis = new FileInputStream( wwwZipFile );
try
{
ZipInputStream zis = new ZipInputStream( new BufferedInputStream( fis ) );
ZipEntry entry;
boolean firstEntryProcessed = false;
int rootFolderPrefixPosn = 0;
while ( ( entry = zis.getNextEntry() ) != null )
{
// Any non-js files are simply copied into the target folder. js files are copied to a temporary
// folder as something else needs to put them into the target folder (there may be processing a js
// file along the way). However we ignore minified files when inflating as by convention, we don't
// want them as part of the project - projects can minify later.
String entryName = entry.getName().substring( rootFolderPrefixPosn );
File entryFile = null;
if ( !entryName.endsWith( "js" ) )
{
if ( !entry.isDirectory() )
{
entryFile = new File( targetFolder, entryName );
}
else if ( !firstEntryProcessed )
{
// Its a directory and it is the first thing in the zip file. We don't want to bother with
// this directory when creating files as we're more interested in merging it into the
// existing target folder.
rootFolderPrefixPosn = entryName.length();
}
}
else if ( !entryName.endsWith( "-min.js" ) )
{
entryFile = new File( jsExpansionFolder, entryName );
jsFiles.add( entryFile );
}
// If we have something interesting to inflate.
if ( entryFile != null )
{
entryFile.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream( entryFile );
BufferedOutputStream dest = null;
try
{
int count;
final int bufferSize = 2048;
byte data[] = new byte[bufferSize];
dest = new BufferedOutputStream( fos, bufferSize );
while ( ( count = zis.read( data, 0, bufferSize ) ) != -1 )
{
dest.write( data, 0, count );
}
dest.flush();
}
finally
{
dest.close();
}
}
firstEntryProcessed = true;
}
}
finally
{
fis.close();
}
// Override the directory's mod time as that will equal the time it was compressed initially. We're not
// interested in that - we're interested to learn whether the source zip file is newer that the directory we
// expand into.
expansionFolder.setLastModified( wwwZipFile.lastModified() );
}
else
{
// Nothing changed. Just return a list of files that were previously expanded.
Collection<File> existingFiles = FileUtils.listFiles( expansionFolder, new String[] { "js" }, true );
for ( File file : existingFiles )
{
if ( !file.getName().endsWith( "-min.js" ) )
{
jsFiles.add( file );
}
}
}
return jsFiles;
}
/**
* @return a list of the files that were found associated with the artifact.
*/
public List<File> getFiles()
{
return files;
}
/**
* @return the location where the files have been expanded to or null otherwise.
*/
public File getExpansionFolder()
{
return expansionFolder;
}
}