All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.andy2003.core.LogFileReplay Maven / Gradle / Ivy

The newest version!
/**
 * 	This file is part of Kayak.
 *
 *	Kayak is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU Lesser General Public License as published by
 *	the Free Software Foundation, either version 3 of the License, or
 *	(at your option) any later version.
 *
 *	Kayak 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.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU Lesser General Public License
 *	along with Kayak.  If not, see .
 *
 */
package com.github.andy2003.core;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;

/**
 *
 * @author Jan-Niklas Meier 
 */
public class LogFileReplay {

    private static final Logger logger = Logger.getLogger(LogFileReplay.class.getCanonicalName());

    private LogFile logFile;
    private TimeSource timeSource;
    private TimeSource.Mode mode;
    private BufferedReader reader;
    private Thread thread;
    private long timeOffset; /* time of the first frame in the log file */
    private long startTime; /* time when the replay was started */
    private HashMap busses;
    private boolean infiniteReplay;

    private final RandomAccessFile file;

    public boolean isInfiniteReplay() {
        return infiniteReplay;
    }

    public void setInfiniteReplay(boolean infiniteReplay) {
        this.infiniteReplay = infiniteReplay;
    }

    public TimeSource getTimeSource() {
        return timeSource;
    }

    public void setTimeSource(TimeSource source) {
        if (this.timeSource != null) {
            this.timeSource.deregister(timeEventReceiver);
        }
        this.timeSource = source;
        this.timeSource.register(timeEventReceiver);
        this.mode = timeSource.getMode();

    }

    /**
     * Connect a bus to the {@link LogFileReplay}. Every log entry with 'name'
     * will be sent to the corresponding bus.
     * @param name Name in the log file
     * @param bus Bus that will be connected to this name
     */
    public void setBus(String name, Bus bus) {
        busses.put(name, bus);
    }

    /**
     * Create a new {@link LogFileReplay} with a specific {@link LogFile}.
     * @param logFile
     */
    public LogFileReplay(LogFile logFile) throws FileNotFoundException {
        this.logFile = logFile;

        busses = new HashMap();
        for (String b : logFile.getBusses()) {
            busses.put(b, null);
        }

        file = new RandomAccessFile(logFile.getFile(), "r");
    }

    /* Seeks the file to the position of the first frame and returns
     * this position
     */
    private long findStartPosition() {
        synchronized(file) {
            try {
                file.seek(0);

                while(true) {
                    long posBefore = file.getFilePointer();
                    String line = file.readLine();
                    if(line.startsWith("(")) {
                        file.seek(posBefore);
                        return posBefore;
                    }
                }
            } catch(IOException ex) {
                    return -1;
            }
        }
    }

    public void seekTo(long pos) {
        if(pos == timeOffset) {
            findStartPosition();
            return;
        }
    }

    private Frame.FrameBusNamePair readNextFrame() {
        synchronized(file) {
            try {
                String line = file.readLine();
                return Frame.fromLogFileNotation(line);
            } catch(IOException ex) {
                return null;
            }
        }
    }

    private void seekToBeginning() {
        logger.log(Level.INFO, "Seeking to begin of file");
        try {
            if(reader != null)
                reader.close();

            InputStream inputStream;
            if (logFile.getCompressed()) {
                inputStream = new GZIPInputStream(new FileInputStream(logFile.getFile()));
            } else {
                inputStream = new FileInputStream(logFile.getFile());
            }

            reader = new BufferedReader(new InputStreamReader(inputStream));

            /* Skip header */
            reader.mark(1024);
            while (true) {
                String line = reader.readLine();
                if (line != null && line.startsWith("(")) {
                    String[] cols = line.split("\\s");
                    timeOffset = (long) (Double.parseDouble((cols[0].substring(1, cols[0].length() - 1))) * 1000);
                    reader.reset();
                    break;
                }
                reader.mark(1024);
            }
        } catch (Exception ex) {
            logger.log(Level.WARNING, "Exception while seeking to begin of file", ex);
        }

        startTime = timeSource.getTime();
    }

    private Runnable myRunnable = new Runnable() {

        private boolean checkMode() {
            if (mode == mode.STOP) {
                return true;
            } else if (mode == mode.PAUSE) {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException ex1) {
                        if (mode == mode.PLAY) {
                            return false;
                        } else if(mode == mode.STOP) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    if (reader.ready()) {
                        if(checkMode())
                            return;
                        String line = reader.readLine();
                        if (line.startsWith("(")) {
                            String[] cols = line.split("\\s");

                            /* check if we have a bus connected for this recorded bus */
                            Bus bus = busses.get(logFile.getAlias(cols[1]));

                            if (bus == null) {
                                continue;
                            }
                            long msecs = (long) (Double.parseDouble((cols[0].substring(1, cols[0].length() - 1))) * 1000) - timeOffset;

                            String[] data = cols[2].split("#");
                            int identifier = Integer.parseInt(data[0], 16);

                            byte[] message = Util.hexStringToByteArray(data[1]);

                            Frame frame;

                            if(data[0].length()<=3) {
                                frame = new Frame(identifier, false, message);
                            } else {
                                frame = new Frame(identifier, true, message);
                            }

                            long timeToWait = msecs - (timeSource.getTime() - startTime);

                            /* if timeToWait is <0 we are to late. if it is >0 we have to wait. This only makes sense if
                             * it is more than a few ms.
                             */
                            if (timeToWait >= 10) {
                                try {
                                    Thread.sleep(timeToWait);
                                } catch (InterruptedException ex) {
                                    if(checkMode())
                                        return;
                                }
                            }

                            bus.sendFrame(frame);
                        } else if(line.startsWith("EVENT")) {
                            String[] cols = line.split("\\s");

                            EventFrame ev;
                            Bus bus = null;

                            if(cols[1].startsWith("(")) { /* timestamp */
                                if(cols[2].startsWith("\"")) { /* timestamp and bus name */
                                    ev = new EventFrame(cols[3].substring(1, cols[3].length()-1));
                                    bus = busses.get(logFile.getAlias(cols[2]));
                                } else { /* no bus name */
                                    ev = new EventFrame(cols[2].substring(1, cols[2].length()-1));
                                }

                                long msecs = (long) (Double.parseDouble((cols[1].substring(1, cols[1].length() - 1))) * 1000) - timeOffset;
                                ev.setTimestamp(msecs);
                                long timeToWait = msecs - (timeSource.getTime() - startTime);

                                if (timeToWait >= 10) {
                                    try {
                                        Thread.sleep(timeToWait);
                                    } catch (InterruptedException ex) {
                                        if(checkMode())
                                            return;
                                    }
                                }
                            } else { /* no timestamp */
                                if(cols[2].startsWith("\"")) { /* bus name */
                                    bus = busses.get(logFile.getAlias(cols[2]));
                                    ev = new EventFrame(cols[2].substring(1, cols[2].length()-1));
                                } else { /* no bus name */
                                    ev = new EventFrame(cols[1].substring(1, cols[1].length()-1));
                                }
                            }

                            if (bus == null) {
                                Set keys = busses.keySet();
                                for(String key : keys) {
                                    busses.get(key).sendEventFrame(ev);
                                }
                            }

                            bus.sendEventFrame(ev);
                        }
                    } else {
                        if (infiniteReplay) {
                            EventFrame ev = new EventFrame("Seeking to beginning");
                            ev.setTimestamp(timeOffset);

                            Set keys = busses.keySet();
                            for(String key : keys) {
                                busses.get(key).sendEventFrame(ev);
                            }

                            seekToBeginning();
                            continue;
                        } else {
                            return;
                        }
                    }


                } catch (IOException ex) {
                    Logger.getLogger(LogFileReplay.class.getName()).log(Level.SEVERE, null, ex);
                }

            }
        }
    };

    private TimeEventReceiver timeEventReceiver = new TimeEventReceiver() {

        @Override
        public void paused() {
            mode = mode.PAUSE;
            thread.interrupt();
        }

        @Override
        public void played() {
            if (mode == mode.STOP) {
                seekToBeginning();
            }

            if (thread == null || !thread.isAlive()) {
                thread = new Thread(myRunnable);
                thread.start();
            } else {
                thread.interrupt();
            }

            mode = mode.PLAY;
        }

        @Override
        public void stopped() {
            mode = mode.STOP;
            if(thread != null && thread.isAlive())
                thread.interrupt();
        }
    };
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy