package jadex.tools.common.modeltree;
import jadex.commons.collection.MultiCollection;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
/**
* A directory-like representation of a jar file.
*/
public class JarAsDirectory extends File
{
//-------- attributes --------
/** The path of the jar file. */
protected String jarpath;
/** The timestamp of the file. */
protected long lastmodified;
/** The entry. */
protected ZipEntry entry;
/** The subentries contained in the entry. */
protected File[] entries;
/** The files for the entry paths (cached for easy access). */
protected Map entryfiles;
//-------- constructors --------
/**
* Create a directory representation of a jar file.
*/
public JarAsDirectory(String jarpath)
{
super(jarpath);
this.jarpath = jarpath;
this.lastmodified = Long.MIN_VALUE;
}
/**
* Create a directory representation of a jar file entry.
*/
public JarAsDirectory(String jarpath, ZipEntry entry)
{
super(jarpath+"!/"+entry.getName());
this.jarpath = jarpath;
this.entry = entry;
this.lastmodified = Long.MIN_VALUE;
}
//-------- File methods --------
public boolean isDirectory()
{
// System.out.println("is directory: "+entry+", "+(entry==null || entry.isDirectory()));
return entry==null || entry.isDirectory();
}
public File[] listFiles(FileFilter filter)
{
File[] ret;
if(entries!=null)
{
List list = new ArrayList();
for(int i=0; i<entries.length; i++)
{
if(filter.accept(entries[i]))
list.add(entries[i]);
}
ret = (File[])list.toArray(new File[list.size()]);
}
else
{
ret = new File[0];
}
// System.out.println("list files: "+entry+", "+SUtil.arrayToString(ret));
return ret;
}
public File[] listFiles(FilenameFilter filter)
{
File[] ret;
if(entries!=null)
{
List list = new ArrayList();
for(int i=0; i<entries.length; i++)
{
if(filter.accept(entries[i].getParentFile(), entries[i].getName()))
list.add(entries[i]);
}
ret = (File[])list.toArray(new File[list.size()]);
}
else
{
ret = new File[0];
}
// System.out.println("list files: "+entry+", "+SUtil.arrayToString(ret));
return ret;
}
public String getAbsolutePath()
{
String ret;
if(entry!=null)
{
if(jarpath.startsWith("/"))
ret = "jar:file:"+jarpath+"!/"+entry.getName();
else
ret = "jar:file:/"+jarpath+"!/"+entry.getName();
}
else
{
ret = jarpath;
}
return ret;
}
public long lastModified()
{
return entry==null ? lastmodified : entry.getTime();
}
//-------- extra methods --------
/**
* Refresh the jar entries.
*/
public synchronized boolean refresh()
{
boolean changed = false;
// Only the root node needs to be refreshed.
if(entry==null && new File(jarpath).lastModified()>lastmodified)
{
changed = true;
this.lastmodified = new File(jarpath).lastModified();
// Read entries into multi-collection (path->entries).
MultiCollection entries = new MultiCollection();
Set contained = new HashSet();
try
{
JarFile jar = new JarFile(jarpath);
Enumeration e = jar.entries();
while(e.hasMoreElements())
{
ZipEntry entry = (ZipEntry)e.nextElement();
boolean finished = false;
while(!finished)
{
String dir = "/";
int slash = entry.getName().lastIndexOf("/", entry.getName().length()-2);
if(slash!=-1)
{
dir = entry.getName().substring(0, slash+1);
}
if(!contained.contains(entry.getName()))
{
entries.put(dir, entry);
contained.add(entry.getName());
}
if(dir.equals("/"))
{
finished = true;
}
else
{
// Add directory entries manually, because some tools (like eclipse) do not include these in the jar.
entry = new ZipEntry(dir);
}
}
}
}
catch(IOException e)
{
e.printStackTrace();
}
// Recursively create files for entries.
this.entryfiles = new HashMap();
this.entries = createFiles("/", entries);
}
// System.out.println("refresh: "+entry+", "+changed);
return changed;
}
/**
* Check if the file exists.
*/
public boolean exists()
{
return true; // hack???
}
/**
* Create the files for an entry.
* Recursive implementation for directory entries.
*/
public File[] createFiles(String key, MultiCollection entries)
{
Collection col = entries.getCollection(key);
JarAsDirectory[] ret = new JarAsDirectory[col.size()];
Iterator it = col.iterator();
for(int i=0; it.hasNext(); i++)
{
ZipEntry entry = (ZipEntry)it.next();
ret[i] = new JarAsDirectory(jarpath, entry);
if(ret[i].isDirectory())
{
ret[i].entries = createFiles(ret[i].entry.getName(), entries);
}
entryfiles.put(entry.getName(), ret[i]);
}
// System.out.println("create files: "+key+", "+SUtil.arrayToString(ret));
return ret;
}
/**
* Get the path to the jar file.
*/
public String getJarPath()
{
return jarpath;
}
/**
* Get the zip entry, if any (file pointer inside jar file).
* The jar file itself (root) has no entry (i.e. entry=null).
*/
public ZipEntry getZipEntry()
{
return entry;
}
/**
* Get a file for an entry path.
*/
public synchronized File getFile(String path)
{
if(entryfiles==null)
refresh();
return (File)entryfiles.get(path);
}
}