Methods Summary |
---|
public static IMergeable[] | load(java.io.File file) // must be consistent with mergeload()
if (file == null) throw new IllegalArgumentException ("null input: file");
return mergeload (file);
|
private static java.lang.String | makeAppVersion(int major, int minor, int build)
final StringBuffer buf = new StringBuffer ();
buf.append (major);
buf.append ('.");
buf.append (minor);
buf.append ('.");
buf.append (build);
return buf.toString ();
|
private static IMergeable[] | mergeload(java.io.File file)
final Logger log = Logger.getLogger ();
final boolean trace1 = log.atTRACE1 ();
final boolean trace2 = log.atTRACE2 ();
final String method = "mergeload";
long start = 0, end;
if (trace1) start = System.currentTimeMillis ();
final IMergeable [] result = new IMergeable [2];
if (! file.exists ())
{
throw new IOException ("input file does not exist: [" + file.getAbsolutePath () + "]");
}
else
{
RandomAccessFile raf = null;
try
{
raf = new RandomAccessFile (file, "r");
// 'file' is a valid existing file, but it could still be of 0 length or otherwise corrupt:
final long length = raf.length ();
if (trace1) log.trace1 (method, "[" + file + "]: file length = " + length);
if (length < FILE_HEADER_LENGTH)
{
throw new IOException ("file [" + file.getAbsolutePath () + "] is corrupt or was not created by " + IAppConstants.APP_NAME);
}
else
{
// TODO: data version checks parallel to persist()
if (length > FILE_HEADER_LENGTH) // return {null, null} in case of equality
{
raf.seek (FILE_HEADER_LENGTH);
// [assertion: file length > FILE_HEADER_LENGTH]
// read entries until the first corrupt entry or the end of the file:
long position = FILE_HEADER_LENGTH;
long entryLength;
long entrystart = 0;
while (true)
{
if (trace2) log.trace2 (method, "[" + file + "]: position " + raf.getFilePointer ());
if (position >= length) break;
entryLength = raf.readLong ();
if ((entryLength <= 0) || (position + entryLength + ENTRY_HEADER_LENGTH > length))
break;
else
{
final byte type = raf.readByte ();
if ((type < 0) || (type >= result.length))
break;
if (trace2) log.trace2 (method, "[" + file + "]: found valid entry of size " + entryLength + " and type " + type);
{
if (trace2) entrystart = System.currentTimeMillis ();
final IMergeable data = readEntry (raf, type, entryLength);
if (trace2) log.trace2 (method, "entry read in " + (System.currentTimeMillis () - entrystart) + " ms");
final IMergeable current = result [type];
if (current == null)
result [type] = data;
else
result [type] = current.merge (data); // note: later entries overrides earlier entries
}
position += entryLength + ENTRY_HEADER_LENGTH;
if ($assert.ENABLED) $assert.ASSERT (raf.getFD ().valid (), "FD invalid");
raf.seek (position);
}
}
}
}
}
finally
{
if (raf != null) try { raf.close (); } catch (Throwable ignore) {}
raf = null;
}
}
if (trace1)
{
end = System.currentTimeMillis ();
log.trace1 (method, "[" + file + "]: file processed in " + (end - start) + " ms");
}
return result;
|
public static ICoverageData | newCoverageData()
return new CoverageData ();
|
public static IMetaData | newMetaData(CoverageOptions options)
return new MetaData (options);
|
private static void | persist(IMergeable data, byte type, java.io.File file)
final Logger log = Logger.getLogger ();
final boolean trace1 = log.atTRACE1 ();
final boolean trace2 = log.atTRACE2 ();
final String method = "persist";
long start = 0, end;
if (trace1) start = System.currentTimeMillis ();
// TODO: 1.4 adds some interesting RAF open mode options as well
// TODO: will this benefit from extra buffering?
// TODO: data version checks
RandomAccessFile raf = null;
try
{
boolean overwrite = false;
boolean truncate = false;
if (file.exists ())
{
// 'file' exists:
if (! file.isFile ()) throw new IOException ("can persist in normal files only: " + file.getAbsolutePath ());
raf = new RandomAccessFile (file, "rw");
// 'file' is a valid existing file, but it could still be of 0 length or otherwise corrupt:
final long length = raf.length ();
if (trace1) log.trace1 (method, "[" + file + "]: existing file length = " + length);
if (length < 4)
{
overwrite = true;
truncate = (length > 0);
}
else
{
// [assertion: file length >= 4]
// check header info before reading further:
final int magic = raf.readInt ();
if (magic != MAGIC)
throw new IOException ("cannot overwrite [" + file.getAbsolutePath () + "]: not created by " + IAppConstants.APP_NAME);
if (length < FILE_HEADER_LENGTH)
{
// it's our file, but the header is corrupt: overwrite
overwrite = true;
truncate = true;
}
else
{
// [assertion: file length >= FILE_HEADER_LENGTH]
// if (! append)
// {
// // overwrite any existing data:
//
// raf.seek (FILE_HEADER_LENGTH);
// writeEntry (raf, FILE_HEADER_LENGTH, data, type);
// }
// else
{
// check data format version info:
final long dataVersion = raf.readLong ();
if (dataVersion != IAppConstants.DATA_FORMAT_VERSION)
{
// read app version info for the error message:
int major = 0, minor = 0, build = 0;
boolean gotAppVersion = false;
try
{
major = raf.readInt ();
minor = raf.readInt ();
build = raf.readInt ();
gotAppVersion = true;
}
catch (Throwable ignore) {}
// TODO: error code here?
if (gotAppVersion)
{
throw new IOException ("cannot merge new data into [" + file.getAbsolutePath () + "]: created by another " + IAppConstants.APP_NAME + " version [" + makeAppVersion (major, minor, build) + "]");
}
else
{
throw new IOException ("cannot merge new data into [" + file.getAbsolutePath () + "]: created by another " + IAppConstants.APP_NAME + " version");
}
}
else
{
// [assertion: file header is valid and data format version is consistent]
raf.seek (FILE_HEADER_LENGTH);
if (length == FILE_HEADER_LENGTH)
{
// no previous data entries: append 'data'
writeEntry (log, raf, FILE_HEADER_LENGTH, data, type);
}
else
{
// [assertion: file length > FILE_HEADER_LENGTH]
// write 'data' starting with the first corrupt entry or the end of the file:
long position = FILE_HEADER_LENGTH;
long entryLength;
while (true)
{
if (trace2) log.trace2 (method, "[" + file + "]: position " + raf.getFilePointer ());
if (position >= length) break;
entryLength = raf.readLong ();
if ((entryLength <= 0) || (position + entryLength + ENTRY_HEADER_LENGTH > length))
break;
else
{
if (trace2) log.trace2 (method, "[" + file + "]: found valid entry of size " + entryLength);
position += entryLength + ENTRY_HEADER_LENGTH;
raf.seek (position);
}
}
if (trace2) log.trace2 (method, "[" + file + "]: adding entry at position " + position);
writeEntry (log, raf, position, data, type);
}
}
}
}
}
}
else
{
// 'file' does not exist:
if (trace1) log.trace1 (method, "[" + file + "]: creating a new file");
final File parent = file.getParentFile ();
if (parent != null) parent.mkdirs ();
raf = new RandomAccessFile (file, "rw");
overwrite = true;
}
if (overwrite)
{
// persist starting from 0 offset:
if ($assert.ENABLED) $assert.ASSERT (raf != null, "raf = null");
if (truncate) raf.seek (0);
writeFileHeader (raf);
if ($assert.ENABLED) $assert.ASSERT (raf.getFilePointer () == FILE_HEADER_LENGTH, "invalid header length: " + raf.getFilePointer ());
writeEntry (log, raf, FILE_HEADER_LENGTH, data, type);
}
}
finally
{
if (raf != null) try { raf.close (); } catch (Throwable ignore) {}
raf = null;
}
if (trace1)
{
end = System.currentTimeMillis ();
log.trace1 (method, "[" + file + "]: file processed in " + (end - start) + " ms");
}
|
public static void | persist(IMetaData data, java.io.File file, boolean merge)
if (data == null) throw new IllegalArgumentException ("null input: data");
if (file == null) throw new IllegalArgumentException ("null input: file");
if (! merge && file.exists ())
{
if (! file.delete ())
throw new IOException ("could not delete file [" + file.getAbsolutePath () + "]");
}
persist (data, TYPE_METADATA, file);
|
public static void | persist(ICoverageData data, java.io.File file, boolean merge)
if (data == null) throw new IllegalArgumentException ("null input: data");
if (file == null) throw new IllegalArgumentException ("null input: file");
if (! merge && file.exists ())
{
if (! file.delete ())
throw new IOException ("could not delete file [" + file.getAbsolutePath () + "]");
}
persist (data, TYPE_COVERAGEDATA, file);
|
public static void | persist(ISessionData data, java.io.File file, boolean merge)
if (data == null) throw new IllegalArgumentException ("null input: data");
if (file == null) throw new IllegalArgumentException ("null input: file");
if (! merge && file.exists ())
{
if (! file.delete ())
throw new IOException ("could not delete file [" + file.getAbsolutePath () + "]");
}
persist (data.getMetaData (), TYPE_METADATA, file);
persist (data.getCoverageData (), TYPE_COVERAGEDATA, file);
|
public static boolean[] | readBooleanArray(java.io.DataInput in)
final int length = in.readInt ();
if (length == NULL_ARRAY_LENGTH)
return null;
else
{
final boolean [] result = new boolean [length];
// read array in reverse order:
for (int i = length; -- i >= 0; )
{
result [i] = in.readBoolean ();
}
return result;
}
|
public static ICoverageData | readCoverageData(java.net.URL url)
ObjectInputStream oin = null;
try
{
oin = new ObjectInputStream (new BufferedInputStream (url.openStream (), 32 * 1024));
return (ICoverageData) oin.readObject ();
}
finally
{
if (oin != null) try { oin.close (); } catch (Exception ignore) {}
}
|
private static IMergeable | readEntry(java.io.RandomAccessFile raf, byte type, long entryLength)
final Object data;
RandomAccessFileInputStream rafin = new RandomAccessFileInputStream (raf, IO_BUF_SIZE); // note: no new file descriptors created here
{
// ObjectInputStream oin = new ObjectInputStream (rafin);
//
// try
// {
// data = oin.readObject ();
// }
// catch (ClassNotFoundException cnfe)
// {
// // TODO: EMMA exception here
// throw new IOException ("could not read data entry: " + cnfe.toString ());
// }
DataInputStream din = new DataInputStream (rafin);
switch (type)
{
case TYPE_METADATA: data = MetaData.readExternal (din);
break;
default /* TYPE_COVERAGEDATA */: data = CoverageData.readExternal (din);
break;
} // end of switch
}
if ($assert.ENABLED) $assert.ASSERT (rafin.getCount () == entryLength, "entry length mismatch: " + rafin.getCount () + " != " + entryLength);
return (IMergeable) data;
|
public static int[] | readIntArray(java.io.DataInput in)
final int length = in.readInt ();
if (length == NULL_ARRAY_LENGTH)
return null;
else
{
final int [] result = new int [length];
// read array in reverse order:
for (int i = length; -- i >= 0; )
{
result [i] = in.readInt ();
}
return result;
}
|
public static IMetaData | readMetaData(java.net.URL url)
ObjectInputStream oin = null;
try
{
oin = new ObjectInputStream (new BufferedInputStream (url.openStream (), 32 * 1024));
return (IMetaData) oin.readObject ();
}
finally
{
if (oin != null) try { oin.close (); } catch (Exception ignore) {}
}
|
public static void | writeBooleanArray(boolean[] array, java.io.DataOutput out)
if (array == null)
out.writeInt (NULL_ARRAY_LENGTH);
else
{
final int length = array.length;
out.writeInt (length);
// write array in reverse order:
for (int i = length; -- i >= 0; )
{
out.writeBoolean (array [i]);
}
}
|
public static void | writeCoverageData(ICoverageData data, java.io.OutputStream out)
// TODO: prevent concurrent modification problems here
ObjectOutputStream oout = new ObjectOutputStream (out);
oout.writeObject (data);
|
private static void | writeEntry(com.vladium.logging.Logger log, java.io.RandomAccessFile raf, long marker, IMergeable data, byte type)
// [unfinished] entry header:
writeEntryHeader (raf, type);
// serialize 'data' starting with the current raf position:
RandomAccessFileOutputStream rafout = new RandomAccessFileOutputStream (raf, IO_BUF_SIZE); // note: no new file descriptors created here
{
// ObjectOutputStream oout = new ObjectOutputStream (rafout);
//
// oout.writeObject (data);
// oout.flush ();
// oout = null;
DataOutputStream dout = new DataOutputStream (rafout);
switch (type)
{
case TYPE_METADATA: MetaData.writeExternal ((MetaData) data, dout);
break;
default /* TYPE_COVERAGEDATA */: CoverageData.writeExternal ((CoverageData) data, dout);
break;
} // end of switch
dout.flush ();
dout = null;
// truncate:
raf.setLength (raf.getFilePointer ());
}
// transact this entry [finish the header]:
raf.seek (marker);
raf.writeLong (rafout.getCount ());
if (DO_FSYNC) raf.getFD ().sync ();
if (log.atTRACE2 ()) log.trace2 ("writeEntry", "entry [" + data.getClass ().getName () + "] length: " + rafout.getCount ());
|
private static void | writeEntryHeader(java.io.DataOutput out, byte type)
out.writeLong (UNKNOWN); // length placeholder
out.writeByte (type);
|
private static void | writeFileHeader(java.io.DataOutput out)
out.writeInt (MAGIC);
out.writeLong (IAppConstants.DATA_FORMAT_VERSION);
out.writeInt (IAppConstants.APP_MAJOR_VERSION);
out.writeInt (IAppConstants.APP_MINOR_VERSION);
out.writeInt (IAppConstants.APP_BUILD_ID);
|
public static void | writeIntArray(int[] array, java.io.DataOutput out)
if (array == null)
out.writeInt (NULL_ARRAY_LENGTH);
else
{
final int length = array.length;
out.writeInt (length);
// write array in reverse order:
for (int i = length; -- i >= 0; )
{
out.writeInt (array [i]);
}
}
|
public static void | writeMetaData(IMetaData data, java.io.OutputStream out)
ObjectOutputStream oout = new ObjectOutputStream (out);
oout.writeObject (data);
|
public static void | writeMetaData(IMetaData data, java.net.URL url)
final URLConnection connection = url.openConnection ();
connection.setDoOutput (true);
OutputStream out = null;
try
{
out = connection.getOutputStream ();
writeMetaData (data, out);
out.flush ();
}
finally
{
if (out != null) try { out.close (); } catch (Exception ignore) {}
}
|