/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2014 Ausenco Engineering Canada Inc.
*
* Licensed 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.
*/
package com.jaamsim.basicsim;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import com.jaamsim.events.EventManager;
import com.jaamsim.events.EventTraceListener;
import com.jaamsim.events.ProcessTarget;
import com.jaamsim.input.Input;
import com.jaamsim.input.InputErrorException;
public class EventRecorder implements EventTraceListener {
private BufferedWriter outputStream;
private int traceLevel;
private final ArrayList<String> traces = new ArrayList<>();
public EventRecorder(String fileName) {
traceLevel = 0;
try {
File backingFileObject = new File(fileName);
backingFileObject.createNewFile();
outputStream = new BufferedWriter(new FileWriter(backingFileObject, false));
}
catch (IOException e) {
throw new InputErrorException("IOException thrown trying to open FileEntity: " + e);
}
catch (IllegalArgumentException e) {
throw new InputErrorException("IllegalArgumentException thrown trying to open File (Should not happen): " + e);
}
catch (SecurityException e) {
throw new InputErrorException("SecurityException thrown trying to open File: " + e);
}
}
private void append(String record) {
StringBuilder rec = new StringBuilder();
for (int i = 0; i < traceLevel; i++) {
rec.append(Input.SEPARATOR);
}
rec.append(record);
traces.add(rec.toString());
}
private void addHeader(String name, long internalTime) {
// Don't write anything if not at level 0
if (traceLevel != 0)
return;
StringBuilder header = new StringBuilder(name).append("\t").append(internalTime);
traces.add(header.toString());
traceLevel++;
}
private void finish(EventManager e) {
if(traceLevel != 1)
return;
traces.add("");
for (String each : traces) {
try {
outputStream.write( each );
outputStream.newLine();
}
catch( IOException ioe ) {}
}
try {
outputStream.flush();
}
catch( IOException ioe ) {}
traces.clear();
traceLevel--;
}
private static final String entClassName = Entity.class.getName();
private static final String evtManClassName = EventManager.class.getName();
static String getWaitDescription() {
StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
int evtManIdx = -1;
// walk out of any EventManager methods
for (int i = 0; i < callStack.length; i++) {
if (callStack[i].getClassName().equals(evtManClassName)) {
evtManIdx = i;
continue;
}
// we have walked through the eventManager methods
if (evtManIdx != -1)
break;
}
// walk past any Entity methods
int entIdx = -1;
for (int i = evtManIdx + 1; i < callStack.length; i++) {
if (callStack[i].getClassName().equals(entClassName)) {
entIdx = i;
continue;
}
break;
}
StackTraceElement elem;
if (entIdx > -1)
elem = callStack[entIdx + 1];
else
elem = callStack[evtManIdx + 1];
return String.format("%s:%s", elem.getClassName(), elem.getMethodName());
}
@Override
public synchronized void traceWait(EventManager e, long curTick, long tick, int priority, ProcessTarget t) {
this.addHeader(e.name, curTick);
traceLevel--;
this.append(String.format("Wait\t%d\t%d\t%s", tick, priority, getWaitDescription()));
this.finish(e);
}
@Override
public synchronized void traceEvent(EventManager e, long curTick, long tick, int priority, ProcessTarget t) {
this.addHeader(e.name, curTick);
this.append(String.format("Event\t%d\t%d\t%s", tick, priority, t.getDescription()));
traceLevel++;
this.finish(e);
}
@Override
public synchronized void traceInterrupt(EventManager e, long curTick, long tick, int priority, ProcessTarget t) {
this.addHeader(e.name, curTick);
this.append(String.format("Int\t%d\t%d\t%s", tick, priority, t.getDescription()));
traceLevel++;
this.finish(e);
}
@Override
public synchronized void traceKill(EventManager e, long curTick, long tick, int priority, ProcessTarget t) {
this.addHeader(e.name, curTick);
this.append(String.format("Kill\t%d\t%d\t%s", tick, priority, t.getDescription()));
this.finish(e);
}
@Override
public synchronized void traceWaitUntil(EventManager e, long tick) {
this.addHeader(e.name, tick);
traceLevel--;
this.append("WaitUntil");
this.finish(e);
}
@Override
public synchronized void traceWaitUntilEnded(EventManager e, long curTick, ProcessTarget t) {
this.addHeader(e.name, curTick);
this.append(String.format("WaitUntilEnded\t%s", t.getDescription()));
this.finish(e);
}
@Override
public synchronized void traceProcessStart(EventManager e, ProcessTarget t, long tick) {
this.addHeader(e.name, tick);
this.append(String.format("StartProcess\t%s", t.getDescription()));
traceLevel++;
this.finish(e);
}
@Override
public synchronized void traceProcessEnd(EventManager e, long tick) {
this.addHeader(e.name, tick);
traceLevel--;
this.append("Exit");
this.finish(e);
}
@Override
public synchronized void traceSchedProcess(EventManager e, long curTick, long tick, int priority, ProcessTarget t) {
this.addHeader(e.name, curTick);
this.append(String.format("SchedProcess\t%d\t%d\t%s", tick, priority, t.getDescription()));
this.finish(e);
}
}