Package de.dfki.km.text20.browserplugin.services.sessionrecorder.impl.xstream

Source Code of de.dfki.km.text20.browserplugin.services.sessionrecorder.impl.xstream.SessionStreamer

/*
* SessionStreamer.java
*
* Copyright (c) 2010, Ralf Biedert, DFKI. All rights reserved.
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301  USA
*
*/
package de.dfki.km.text20.browserplugin.services.sessionrecorder.impl.xstream;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.ElementMap;
import org.simpleframework.xml.Root;

import com.thoughtworks.xstream.XStream;

import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.AbstractSessionEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.BrainTrackingEventContainer;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.CallFunctionEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.ElementGeometryEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.ElementMetaInformation;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.ExecuteJSEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.EyeTrackingEventContainer;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.GeometryEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.GetPreferenceEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.ImageEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.InitEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.MarkEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.MouseClickEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.MouseMotionEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.PropertyEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.RegisterListenerEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.RemoveListenerEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.ScreenSizeEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.SetPreferenceEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.UpdateElementFlagEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.events.ViewportEvent;
import de.dfki.km.text20.browserplugin.services.sessionrecorder.util.metadata.DisplacementRegion;
import de.dfki.km.text20.services.trackingdevices.brain.BrainTrackingEvent;
import de.dfki.km.text20.services.trackingdevices.eyes.EyeTrackingEvent;

/**
* @author buhl
*
*/
@Root
public class SessionStreamer implements Serializable {
    /** Serialization version */
    private static final int VERSION = 200;

    /**  */
    private static final long serialVersionUID = -3269345193816331063L;

    /** Our logger*/
    protected final Logger logger = Logger.getLogger(this.getClass().getName());

    /** XStream used for serialization */
    private final XStream xstream = new XStream();

    /**
     * set the alias names for the provided XStream object
     * to tweak the xml output by replacing the full qualified object names
     * with shorter equivalents
     *
     * @param xstream
     *
     */
    public static void setAlias(final XStream xstream) {
        xstream.alias("Record", SessionStreamer.class);
        xstream.alias("ViewPort", ViewportEvent.class);
        xstream.alias("InitEvent", InitEvent.class);
        xstream.alias("ImageEvent", ImageEvent.class);
        xstream.alias("ElementGeometryEvent", ElementGeometryEvent.class);
        xstream.alias("MarkEvent", MarkEvent.class);
        xstream.alias("TrackingEvent", EyeTrackingEvent.class);
        xstream.alias("CallFunctionEvent", CallFunctionEvent.class);
        xstream.alias("ElementMetaInformation", ElementMetaInformation.class);
        xstream.alias("ExecuteJSEvent", ExecuteJSEvent.class);
        xstream.alias("GeometryEvent", GeometryEvent.class);
        xstream.alias("GetPreferenceEvent", GetPreferenceEvent.class);
        xstream.alias("MouseClickEvent", MouseClickEvent.class);
        xstream.alias("MouseMotionEvent", MouseMotionEvent.class);
        xstream.alias("RegisterListenerEvent", RegisterListenerEvent.class);
        xstream.alias("RemoveListenerEvent", RemoveListenerEvent.class);
        xstream.alias("SetPreferenceEvent", SetPreferenceEvent.class);
        xstream.alias("EyeTrackingEventContainer", EyeTrackingEventContainer.class);
        xstream.alias("BrainTrackingEventContainer", BrainTrackingEventContainer.class);
        xstream.alias("UpdateElementFlagEvent", UpdateElementFlagEvent.class);
        xstream.alias("DisplacementRegion", DisplacementRegion.class);
        xstream.alias("ScreenSizeEvent", ScreenSizeEvent.class);
        xstream.alias("PropertyEvent", PropertyEvent.class);
    }

    /** List of occured events */
    @ElementList
    List<AbstractSessionEvent> allEvents = new ArrayList<AbstractSessionEvent>();

    @ElementList(required = false)
    List<DisplacementRegion> fixationDisplacementRegions = new ArrayList<DisplacementRegion>();

    /** */
    Point lastKnownMousePosition = new Point();

    /** Size of the screen when recording started */
    @Element
    Dimension screenSize;

    @ElementMap(required = false)
    Map<String, String> sessionProperties = new HashMap<String, String>();

    /** Event queue to for things that go to the file */
    LinkedBlockingQueue<AbstractSessionEvent> eventQueue = new LinkedBlockingQueue<AbstractSessionEvent>();

    /** Output stream we use to write our results */
    ObjectOutputStream out;

    /** If set will be used to set the next event time */
    private Date nextDate;

    /**
     * Create a new session record.
     *
     * @param screenSize
     * @param filename
     * @param date
     */
    public SessionStreamer(final Dimension screenSize, final String filename,
                           final Date date) {

        this.screenSize = screenSize;
        SessionStreamer.setAlias(this.xstream);

        try {
            this.logger.fine("Create our output file " + filename);

            // FIXED: #26
            this.out = this.xstream.createObjectOutputStream(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), "UTF-8")));

            // this.out = this.xstream.createObjectOutputStream(new ZOutputStream(new FileOutputStream(filename), JZlib.Z_BEST_COMPRESSION));
        } catch (final IOException e) {
            e.printStackTrace();
        }

        // Put initial events
        nextDate(date);
        addEvent(new InitEvent(VERSION));
        nextDate(date);
        addEvent(new ScreenSizeEvent(screenSize));
        nextDate(date);

        // Generate our unique session id
        generateUniqueSessionID();

        // Create our session writer
        final Thread writerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    // Get number of events to write
                    int size = SessionStreamer.this.eventQueue.size();

                    // Write every event
                    for (int i = 0; i < size; i++) {
                        AbstractSessionEvent next = null;
                        try {
                            next = SessionStreamer.this.eventQueue.take();
                        } catch (InterruptedException e) {
                            //
                        }
                        addToStream(next);
                    }

                    // And flush our stream when we're done;
                    flush();

                    // Wait some time (TODO: Fix this, so that even for small apps using this plugin no event get lost when they quit instantly)
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        writerThread.setDaemon(true);
        writerThread.start();
    }

    /**
     * @param function
     */
    public void callFunction(final String function) {
        addEvent(new CallFunctionEvent(function));
    }

    /**
     * @param function
     * @param args
     */
    public void executeJSFunction(final String function, final String[] args) {
        addEvent(new ExecuteJSEvent(function, args));
    }

    /**
     * @return the allEvents
     */
    public List<AbstractSessionEvent> getAllEvents() {
        return this.allEvents;
    }

    /**
     *
     * @param key
     * @param deflt
     */
    public void getPreference(final String key, final String deflt) {
        addEvent(new GetPreferenceEvent(key, deflt));
    }

    /**
     * @return .
     * @see java.util.Map#get(java.lang.Object)
     */
    public Map<String, String> getProperties() {
        return this.sessionProperties;
    }

    /**
     * @return the screenSize
     */
    public Dimension getScreenSize() {
        return this.screenSize;
    }

    /**
     * @param tag
     */
    public void markLog(final String tag) {
        addEvent(new MarkEvent(tag));

    }

    /**
     * @param type
     * @param button
     */
    public void mouseClickEvent(final int type, final int button) {
        addEvent(new MouseClickEvent(this.lastKnownMousePosition.x, this.lastKnownMousePosition.y, type, button));
    }

    /**
     * @param x
     * @param y
     * @param type
     * @param button
     */
    public void mouseClickEvent(final int x, final int y, final int type, final int button) {
        addEvent(new MouseClickEvent(x, y, type, button));
    }

    /**
     * @param x
     * @param y
     *
     */
    public void mouseMovement(final int x, final int y) {
        this.lastKnownMousePosition.x = x;
        this.lastKnownMousePosition.y = y;
        addEvent(new MouseMotionEvent(x, y));
    }

    /**
     *
     * @param file
     */
    public void newImage(final String file) {
        addEvent(new ImageEvent(file));
    }

    /**
     * @param key
     * @param value
     * @return .S
     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
     */
    public String putProperty(final String key, final String value) {
        addEvent(new PropertyEvent(key, value));
        return this.sessionProperties.put(key, value);
    }

    /**
     * @param type
     * @param listener
     */
    public void registerListener(final String type, final String listener) {
        addEvent(new RegisterListenerEvent(type, listener));
    }

    /**
     * @param listener
     */
    public void removeListener(final String listener) {
        addEvent(new RemoveListenerEvent(listener));

    }

    /**
     * @param key
     * @param value
     */
    public void setPreference(final String key, final String value) {
        addEvent(new SetPreferenceEvent(key, value));
    }

    /**
     *
     * @param trackingEvent
     */
    public void trackingEvent(final EyeTrackingEvent trackingEvent) {
        addEvent(new EyeTrackingEventContainer(trackingEvent));
    }

    /**
     *
     * @param p
     */
    public void updateDocumentViewport(final Point p) {
        addEvent(new ViewportEvent(p));
    }

    /**
     * @param id
     * @param flag
     * @param value
     */
    public void updateElementFlag(final String id, final String flag, final boolean value) {
        addEvent(new UpdateElementFlagEvent(id, flag, value));
    }

    /**
     *
     * @param id
     * @param type
     * @param content
     * @param r
     */
    public void updateElementGeometry(final String id, final String type,
                                      final String content, final Rectangle r) {

        addEvent(new ElementGeometryEvent(id, type, content, r));
    }

    /**
     *
     * @param r
     */
    public void updateGeometry(final Rectangle r) {
        addEvent(new GeometryEvent(r));
    }

    /**
     * Writes this object to a xml stream
     * @param evt
     */
    protected synchronized void addToStream(final AbstractSessionEvent evt) {
        if (evt == null) return;

        AccessController.doPrivileged(new PrivilegedAction<AbstractSessionEvent>() {
            @Override
            public AbstractSessionEvent run() {
                try {
                    SessionStreamer.this.out.writeObject(evt);
                } catch (final IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    /**
     * Writes this object to a xml stream
     * @param evt
     */
    protected synchronized void flush() {

        AccessController.doPrivileged(new PrivilegedAction<AbstractSessionEvent>() {
            @Override
            public AbstractSessionEvent run() {
                try {
                    SessionStreamer.this.out.flush();
                } catch (final IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    /**
     * @param in
     * @return .
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static AbstractSessionEvent loadFromStream(final ObjectInputStream in)
                                                                                 throws IOException,
                                                                                 ClassNotFoundException {
        return (AbstractSessionEvent) in.readObject();
    }

    /**
     * Generates a unique session id.
     */
    private void generateUniqueSessionID() {
        final long currentTime = System.currentTimeMillis();
        final long random = Math.abs(new Random().nextLong());

        final String id = currentTime + "-" + random;

        putProperty("##SID", id);
    }

    /**
     *
     * @param evt
     */
    protected synchronized void addEvent(final AbstractSessionEvent evt) {

        // Override date if we have one
        if (this.nextDate != null) {
            evt.originalEventTime = this.nextDate.getTime();
        }

        this.eventQueue.add(evt);

        this.nextDate = null;
    }

    /**
     * @return the fixationDisplacementRegions
     */
    public synchronized List<DisplacementRegion> getFixationDisplacementRegions() {
        return this.fixationDisplacementRegions;
    }

    /**
     * @param fixationDisplacementRegions the fixationDisplacementRegions to set
     */
    public synchronized void setFixationDisplacementRegions(final List<DisplacementRegion> fixationDisplacementRegions) {
        this.fixationDisplacementRegions = fixationDisplacementRegions;
    }

    /**
     * @param id
     * @param key
     * @param value
     */
    public void updateMetaInformation(final String id, final String key,
                                      final String value) {
        addEvent(new ElementMetaInformation(id, key, value));
    }

    /**
     * @param date
     */
    public void nextDate(Date date) {
        this.nextDate = date;
    }

    /**
     * @param event2
     */
    public void brainTrackingEvent(BrainTrackingEvent event2) {
        addEvent(new BrainTrackingEventContainer(event2));
    }

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        final SessionStreamer ss = new SessionStreamer(new Dimension(800, 800), "/tmp/1.zs", new Date());
        Random r = new Random();
        for (int i = 0; i < 10000; i++) {
            ss.updateGeometry(new Rectangle(r.nextInt(), r.nextInt(), r.nextInt(), r.nextInt()));
        }
        Thread.sleep(3000);
    }
}
TOP

Related Classes of de.dfki.km.text20.browserplugin.services.sessionrecorder.impl.xstream.SessionStreamer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.