blob: 9d197ae8cf5eea6cf173ca2748cb53bcf44d2c41 [file] [log] [blame]
/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
*
* This program and the accompanying materials are made available under
* the terms of the Common Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/cpl-v10.html
*
* $Id: SourcePathCache.java,v 1.1.1.1 2004/05/09 16:57:39 vlad_r Exp $
*/
package com.vladium.emma.report;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.vladium.util.asserts.$assert;
// ----------------------------------------------------------------------------
/**
* @author Vlad Roubtsov, (C) 2003
*/
public
final class SourcePathCache
{
// public: ................................................................
// TODO: use soft cache for m_packageCache?
/**
* @param sourcepath [can be empty]
*/
public SourcePathCache (final String [] sourcepath, final boolean removeNonExistent)
{
if (sourcepath == null) throw new IllegalArgumentException ("null input: sourcepath");
final List _sourcepath = new ArrayList (sourcepath.length);
for (int i = 0; i < sourcepath.length; ++ i)
{
final File dir = new File (sourcepath [i]);
if (! removeNonExistent || (dir.isDirectory () && dir.exists ()))
_sourcepath.add (dir);
}
m_sourcepath = new File [_sourcepath.size ()];
_sourcepath.toArray (m_sourcepath);
m_packageCache = new HashMap ();
}
/**
* @param sourcepath [can be empty]
*/
public SourcePathCache (final File [] sourcepath, final boolean removeNonExistent)
{
if (sourcepath == null) throw new IllegalArgumentException ("null input: sourcepath");
final List _sourcepath = new ArrayList (sourcepath.length);
for (int i = 0; i < sourcepath.length; ++ i)
{
final File dir = sourcepath [i];
if (! removeNonExistent || (dir.isDirectory () && dir.exists ()))
_sourcepath.add (dir);
}
m_sourcepath = new File [_sourcepath.size ()];
_sourcepath.toArray (m_sourcepath);
m_packageCache = new HashMap ();
}
/**
* @return absolute pathname [null if 'name' was not found in cache]
*/
public synchronized File find (final String packageVMName, final String name)
{
if (packageVMName == null) throw new IllegalArgumentException ("null input: packageVMName");
if (name == null) throw new IllegalArgumentException ("null input: name");
if (m_sourcepath.length == 0) return null;
CacheEntry entry = (CacheEntry) m_packageCache.get (packageVMName);
if (entry == null)
{
entry = new CacheEntry (m_sourcepath.length);
m_packageCache.put (packageVMName, entry);
}
final Set [] listings = entry.m_listings;
for (int p = 0; p < listings.length; ++ p)
{
Set listing = listings [p];
if (listing == null)
{
listing = faultListing (m_sourcepath [p], packageVMName);
listings [p] = listing;
}
// TODO: this is case-sensitive at this point
if (listing.contains (name))
{
final File relativeFile = new File (packageVMName.replace ('/', File.separatorChar), name);
return new File (m_sourcepath [p], relativeFile.getPath ()).getAbsoluteFile ();
}
}
return null;
}
// protected: .............................................................
// package: ...............................................................
// private: ...............................................................
private static final class CacheEntry
{
CacheEntry (final int size)
{
m_listings = new Set [size];
}
final Set /* String */ [] m_listings;
} // end of nested class
// NOTE: because java.io.* implements file filtering in bytecode
// there is no real perf advantage in using a filter here (I might
// as well do list() and filter the result myself
private static final class FileExtensionFilter implements FileFilter
{
public boolean accept (final File file)
{
if ($assert.ENABLED) $assert.ASSERT (file != null, "file = null");
if (file.isDirectory ()) return false; // filter out directories
final String name = file.getName ();
final int lastDot = name.lastIndexOf ('.');
if (lastDot <= 0) return false;
// [assertion: lastDot > 0]
// note: match is case sensitive
return m_extension.equals (name.substring (lastDot));
}
public String toString ()
{
return super.toString () + ", extension = [" + m_extension + "]";
}
FileExtensionFilter (final String extension)
{
if (extension == null)
throw new IllegalArgumentException ("null input: extension");
// ensure starting '.':
final String canonical = canonicalizeExtension (extension);
if (extension.length () <= 1)
throw new IllegalArgumentException ("empty input: extension");
m_extension = canonical;
}
private static String canonicalizeExtension (final String extension)
{
if (extension.charAt (0) != '.')
return ".".concat (extension);
else
return extension;
}
private final String m_extension;
} // end of nested class
private Set /* String */ faultListing (final File dir, final String packageVMName)
{
if ($assert.ENABLED) $assert.ASSERT (dir != null, "dir = null");
if ($assert.ENABLED) $assert.ASSERT (packageVMName != null, "packageVMName = null");
final File packageFile = new File (dir, packageVMName.replace ('/', File.separatorChar));
final File [] listing = packageFile.listFiles (FILE_EXTENSION_FILTER);
if ((listing == null) || (listing.length == 0))
return Collections.EMPTY_SET;
else
{
final Set result = new HashSet (listing.length);
for (int f = 0; f < listing.length; ++ f)
{
result.add (listing [f].getName ());
}
return result;
}
}
private final File [] m_sourcepath; // never null
private final Map /* packageVMName:String->CacheEntry */ m_packageCache; // never null
private static final FileExtensionFilter FILE_EXTENSION_FILTER; // set in <clinit>
static
{
FILE_EXTENSION_FILTER = new FileExtensionFilter (".java");
}
} // end of class
// ----------------------------------------------------------------------------