/*
* JCarder -- cards Java programs to keep threads disentangled
*
* Copyright (C) 2006-2007 Enea AB
* Copyright (C) 2007 Ulrik Svensson
* Copyright (C) 2007 Joel Rosdahl
*
* This program is made available under the GNU GPL version 2, with a special
* exception for linking with JUnit. See the accompanying file LICENSE.txt for
* details.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*/
package com.enea.jcarder.common.events;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import net.jcip.annotations.ThreadSafe;
import com.enea.jcarder.util.Counter;
import com.enea.jcarder.util.logging.Logger;
import static com.enea.jcarder.common.events.EventFileReader.EVENT_LENGTH;
@ThreadSafe
public final class EventFileWriter implements LockEventListenerIfc {
private final ByteBuffer mBuffer =
ByteBuffer.allocateDirect(EVENT_LENGTH * 1024);
private final FileChannel mFileChannel;
private final Logger mLogger;
private final Counter mWrittenLockEvents;
private boolean mShutdownHookExecuted = false;
public EventFileWriter(Logger logger, File file) throws IOException {
mLogger = logger;
mLogger.info("Opening for writing: " + file.getAbsolutePath());
RandomAccessFile raFile = new RandomAccessFile(file, "rw");
raFile.setLength(0);
mFileChannel = raFile.getChannel();
mWrittenLockEvents = new Counter("Written Lock Events",
mLogger,
100000);
writeHeader();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() { shutdownHook(); }
});
}
private void writeHeader() throws IOException {
mBuffer.putLong(EventFileReader.MAGIC_COOKIE);
mBuffer.putInt(EventFileReader.MAJOR_VERSION);
mBuffer.putInt(EventFileReader.MINOR_VERSION);
writeBuffer();
}
public synchronized void onLockEvent(int lockId,
int lockingContextId,
int lastTakenLockId,
int lastTakenLockingContextId,
long threadId) throws IOException {
mBuffer.putInt(lockId);
mBuffer.putInt(lockingContextId);
mBuffer.putInt(lastTakenLockId);
mBuffer.putInt(lastTakenLockingContextId);
mBuffer.putLong(threadId);
mWrittenLockEvents.increment();
if (mBuffer.remaining() < EVENT_LENGTH || mShutdownHookExecuted) {
writeBuffer();
}
}
private void writeBuffer() throws IOException {
mBuffer.flip();
mFileChannel.write(mBuffer);
while (mBuffer.hasRemaining()) {
Thread.yield();
mFileChannel.write(mBuffer);
}
mBuffer.clear();
}
public synchronized void close() throws IOException {
writeBuffer();
mFileChannel.close();
}
private synchronized void shutdownHook() {
try {
if (mFileChannel.isOpen()) {
writeBuffer();
}
} catch (IOException e) {
e.printStackTrace();
}
mShutdownHookExecuted = true;
}
}