org.mitre.muc.callisto.session.SessionLogger.java Source code

Java tutorial

Introduction

Here is the source code for org.mitre.muc.callisto.session.SessionLogger.java

Source

/*
 * Copyright (c) 2002-2006 The MITRE Corporation
 * 
 * Except as permitted below
 * ALL RIGHTS RESERVED
 * 
 * The MITRE Corporation (MITRE) provides this software to you without
 * charge to use for your internal purposes only. Any copy you make for
 * such purposes is authorized provided you reproduce MITRE's copyright
 * designation and this License in any such copy. You may not give or
 * sell this software to any other party without the prior written
 * permission of the MITRE Corporation.
 * 
 * The government of the United States of America may make unrestricted
 * use of this software.
 * 
 * This software is the copyright work of MITRE. No ownership or other
 * proprietary interest in this software is granted you other than what
 * is granted in this license.
 * 
 * Any modification or enhancement of this software must inherit this
 * license, including its warranty disclaimers. You hereby agree to
 * provide to MITRE, at no charge, a copy of any such modification or
 * enhancement without limitation.
 * 
 * MITRE IS PROVIDING THE PRODUCT "AS IS" AND MAKES NO WARRANTY, EXPRESS
 * OR IMPLIED, AS TO THE ACCURACY, CAPABILITY, EFFICIENCY,
 * MERCHANTABILITY, OR FUNCTIONING OF THIS SOFTWARE AND DOCUMENTATION. IN
 * NO EVENT WILL MITRE BE LIABLE FOR ANY GENERAL, CONSEQUENTIAL,
 * INDIRECT, INCIDENTAL, EXEMPLARY OR SPECIAL DAMAGES, EVEN IF MITRE HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You accept this software on the condition that you indemnify and hold
 * harmless MITRE, its Board of Trustees, officers, agents, and
 * employees, from any and all liability or damages to third parties,
 * including attorneys' fees, court costs, and other related costs and
 * expenses, arising out of your use of this software irrespective of the
 * cause of said liability.
 * 
 * The export from the United States or the subsequent reexport of this
 * software is subject to compliance with United States export control
 * and munitions control restrictions. You agree that in the event you
 * seek to export this software you assume full responsibility for
 * obtaining all necessary export licenses and approvals and for assuring
 * compliance with applicable reexport restrictions.
 */

package org.mitre.muc.callisto.session;

import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedWriter;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.text.ParsePosition;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import java.util.WeakHashMap;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import org.dom4j.Document;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

import org.mitre.jawb.Jawb;
import org.mitre.jawb.gui.JawbDocument;
import org.mitre.jawb.gui.GUIUtils;
import org.mitre.jawb.prefs.Preferences;
import org.mitre.jawb.tasks.Task;

/**
 * Simple timer dialog which has a pause button can store data.
 */
public class SessionLogger {

    private static final int DEBUG = 0;

    private static final String SESSION_LOG_KEY = "callisto.session.log";

    public static final Object TIMER_KEY = SESSION_LOG_KEY + ".timer";
    public static final String GEOMETRY_KEY = SESSION_LOG_KEY;

    public static final String SESSION_LOG_DIR_PREFERENCE = SESSION_LOG_KEY + ".dir";
    public static final String SESSION_LOG_ENABLED_PREFERENCE = SESSION_LOG_KEY + ".enabled";

    private static final String ROOT_NAME = "session-log";

    private static final SimpleDateFormat isoPoint;
    private static final SimpleDateFormat isoPeriod;

    static {
        isoPoint = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        isoPeriod = new SimpleDateFormat("'P'HH:mm:ss");
        isoPeriod.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

    private Date tempDate;
    private ParsePosition tempPos;
    private MyDocListener docListener;
    private SessionLogFrame logFrame;
    private JawbDocument doc;

    private File logDir = null;
    private WeakHashMap logFileMap = new WeakHashMap();
    private SAXReader xmlReader = new SAXReader();

    /** Create a session logger, including a Frame to display state. Frame is
     * initially not visible */
    public SessionLogger() {
        tempDate = new Date();
        tempPos = new ParsePosition(0);
        docListener = new MyDocListener();
        logFrame = new SessionLogFrame();
        logFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        logFrame.setStopEnabled(false);
        // we can't disable close decoration so warn users who try.
        logFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                String msg = "Closing the session logger is disabled.\n"
                        + "To disable: close document and turn off logging.";
                JOptionPane.showMessageDialog(logFrame, msg, "Session Logger", JOptionPane.INFORMATION_MESSAGE);
            }
        });
        // listen for movements and window hide/show to store geomerty
        logFrame.addComponentListener(new ComponentAdapter() {
            public void componentMoved(ComponentEvent e) {
                storeGeometry();
            }

            public void componentResized(ComponentEvent e) {
                storeGeometry();
            }

            private void storeGeometry() {
                GUIUtils.storeGeometry(logFrame, GEOMETRY_KEY);
            }
        });
        GUIUtils.loadGeometry(logFrame, GEOMETRY_KEY);

        Preferences prefs = Jawb.getPreferences();
        String dir = prefs.getPreference(SESSION_LOG_DIR_PREFERENCE);
        logDir = initLogDir(dir);
        prefs.setPreference(SESSION_LOG_DIR_PREFERENCE, ((logDir == null) ? null : logDir.toURI().toString()));
    }

    /** Finds the appropriate directory for log files, creating it if needed. */
    private File initLogDir(String tryURI) {
        String dir = tryURI;
        File dirFile = null;
        String badDir = null;

        if (dir != null) {
            try {
                dirFile = new File(new URI(dir));
                if (isBadLocation(dirFile))
                    dirFile = null;
            } catch (Exception e) {
                dirFile = null;
            }
        }
        if (dirFile == null) {
            badDir = dir;
            try {
                dir = System.getProperty("user.home") + File.separator + ".callisto" + File.separator + ROOT_NAME;
                dirFile = new File(dir);
                if (isBadLocation(dirFile))
                    dirFile = null;
            } catch (Exception e) {
                dirFile = null;
            }
        }
        if (dirFile == null) {
            String badList = "director";
            if (badDir != null && !badDir.equals(dir))
                badList = "ies:\n\n" + badDir + "\n" + dir;
            else
                badList = "y\n\n" + dir;
            System.err.println("Session Log Disabled: unable to create logs");
            GUIUtils.showError("Unable to create or use log " + badList + "\n\nLog files will NOT be kept!");
        } else {
            System.err.println("Session Log Dir      = " + dirFile);
        }
        return dirFile;
    }

    /** Utility to check a dir or create it, returns true if dir exists and is
     * writable upon return. */
    private boolean isBadLocation(File dir) {
        return ((dir.exists() && (!dir.canWrite() || dir.isFile())) || (!dir.exists() && !dir.mkdirs()));
    }

    /** Update the SessionLogFrame from attributes in the document. The timer is
     * added to the log frame in case it is being changed or removed. */
    private void updateLogFrame() {
        String fileName = null;
        String location = null;
        String id = null;
        Timer timer = null;

        if (doc != null) {
            timer = (Timer) doc.getClientProperty(TIMER_KEY);
            fileName = doc.getName();
            // RK 2/6/04 this seems to be crashing so I added this test
            // but I think it is a bug that this is null when updateLF is called
            if (timer != null)
                id = timer.getId();
            URI uri = doc.getAtlasURI();
            if (uri == null)
                uri = doc.getSignalURI();
            if (uri == null)
                uri = doc.getExternalURI();
            if (uri != null)
                location = uri.toString();
        }
        logFrame.setAttribute(SessionLogFrame.FILE_NAME, fileName);
        logFrame.setAttribute(SessionLogFrame.SESSION_ID, id);
        logFrame.setAttribute(SessionLogFrame.LOCATION, location);

        logFrame.setTimer(timer);
        logFrame.pack();
        logFrame.setVisible(doc != null);
    }

    /** Return currently JawbDocument. */
    public JawbDocument getJawbDocument() {
        return doc;
    }

    /** Change the document this Logger is tracking. A listener is added to
     * the document and the log frame is updated. */
    public void setJawbDocument(JawbDocument doc) {
        Preferences prefs = Jawb.getPreferences();
        JawbDocument oldDoc = getJawbDocument();

        if (oldDoc != null) {
            oldDoc.removePropertyChangeListener(docListener);
            logFrame.setVisible(false);
            Timer timer = (Timer) oldDoc.getClientProperty(TIMER_KEY);
            if (timer != null) {
                timer.pause(true);
                try {
                    if (prefs.getBoolean(SESSION_LOG_ENABLED_PREFERENCE))
                        updateLog(oldDoc, timer);
                } catch (IOException e) {
                    Throwable x = e;
                    if (e.getCause() != null)
                        x = e.getCause();
                    GUIUtils.showError("Unable to log session:\n" + x.getMessage());
                }
            }
        }

        this.doc = doc;

        if (doc != null) {
            doc.addPropertyChangeListener(docListener);
            if (prefs.getBoolean(SESSION_LOG_ENABLED_PREFERENCE)) {
                Timer timer = (Timer) doc.getClientProperty(TIMER_KEY);
                if (timer == null) {
                    timer = new Timer();
                    doc.putClientProperty(TIMER_KEY, timer);
                }
                timer.start(); // equiv to timer.pause(false)
            }
        }
        updateLogFrame();
    }

    /** Utility to generate a log file in the right directory. */
    private File getLogFile(File dir, String taskName) {
        return new File(logDir, taskName.replaceAll("\\.", "_") + ".log.xml");
    }

    /*
     * Write the current session to the log. Updates the correct session entry
     * for the current file.  The 'file' is determined by the URLs available in
     * the doc: AtlasURI, SignalURI and ExportURI are tried in that order. Log
     * file is determined by task. If the file and or session entries are not
     * present, they are created.
     */
    private void updateLog(JawbDocument doc, Timer timer) throws IOException {

        if (doc == null || timer == null)
            return;

        URI uri = doc.getAtlasURI();
        if (uri == null)
            uri = doc.getSignalURI();
        if (uri == null)
            uri = doc.getExternalURI();

        File log = (File) logFileMap.get(uri);
        if (log == null)
            log = getLogFile(logDir, doc.getTask().getName());

        Document xdoc = parseXML(log);

        Element root = xdoc.getRootElement();
        Element file = getFileElement(root, uri);
        Element session = getSessionElement(file, timer);

        tempDate.setTime(timer.getStartTime());
        session.addAttribute("start", isoPoint.format(tempDate));
        tempDate.setTime(timer.getStopTime());
        session.addAttribute("stop", isoPoint.format(tempDate));
        tempDate.setTime(timer.getPauseDuration());
        session.addAttribute("pause", isoPeriod.format(tempDate));
        tempDate.setTime(timer.getDuration());
        session.addAttribute("duration", isoPeriod.format(tempDate));

        // sum the duration for the file element
        long duration = 0;
        for (Iterator i = getSessionIterator(file); i.hasNext();) {
            session = (Element) i.next();
            tempPos.setIndex(0);
            String durString = session.attributeValue("duration");
            if (durString != null) {
                Date dur = isoPeriod.parse(durString, tempPos);
                if (dur != null)
                    duration += dur.getTime();
            }
        }
        tempDate.setTime(duration);
        file.addAttribute("duration", isoPeriod.format(tempDate));

        OutputStream out = new BufferedOutputStream(new FileOutputStream(log));
        dumpXML(xdoc, out);
        out.close();
    }

    /**
     * Load the specified document.
     * @throw IOException to wrapper any dom4j errors
     */
    private Document parseXML(File aFile) throws IOException {
        Document xdoc = null;
        if (aFile.canRead()) {
            try {
                xdoc = xmlReader.read(aFile);
            } catch (DocumentException de) {
                IOException x = new IOException();
                x.initCause(de);
                throw x;
            }
        } else {
            Element root = DocumentHelper.createElement(ROOT_NAME);
            xdoc = DocumentHelper.createDocument(root);
        }
        return xdoc;
    }

    /** Retrieves existing file element or creates a new one. */
    private Element getFileElement(Element root, URI uri) {
        XPath xpath = DocumentHelper.createXPath("file[@uri='" + uri.toString() + "']");
        List results = xpath.selectNodes(root);

        Element element = null;
        if (results.isEmpty()) {
            element = root.addElement("file");
            element.addAttribute("uri", uri.toString());
        } else {
            element = (Element) results.get(0);
        }

        return element;
    }

    /** Retrieves existing session element or creates a new one. */
    private Element getSessionElement(Element file, Timer timer) {
        XPath xpath = DocumentHelper.createXPath("session[@id='" + timer.getId() + "']");
        List results = xpath.selectNodes(file);

        Element element = null;
        if (results.isEmpty()) {
            element = file.addElement("session");
            element.addAttribute("id", String.valueOf(timer.getId()));
        } else {
            element = (Element) results.get(0);
        }

        return element;
    }

    /** Retrieves iterator over sessions elements */
    private Iterator getSessionIterator(Element file) {
        XPath xpath = DocumentHelper.createXPath("session");
        List results = xpath.selectNodes(file);
        return results.iterator();
    }

    /** Write xml file to specified stream. */
    private void dumpXML(Document xdoc, OutputStream out) throws IOException {
        OutputFormat outformat = OutputFormat.createPrettyPrint();
        outformat.setEncoding("UTF-8");
        XMLWriter writer = new XMLWriter(out, outformat);
        writer.write(xdoc);
        writer.flush();
    }

    /**********************************************************************/

    /** Added to current JawbDocument to update the SessionLogFrame for doc
     * changes */
    private class MyDocListener implements PropertyChangeListener {
        public void propertyChange(PropertyChangeEvent e) {
            updateLogFrame();
        }
    }

    /** testing only 
    public static void main(String[] args) throws IOException {
      List tasks = Jawb.getTasks();
        
      SessionLogger logger = new SessionLogger();
      URI base = new File(System.getProperty("user.home")).toURI();
        
      Task task = null;
      for (Iterator i=tasks.iterator(); i.hasNext(); ) {
        task = (Task) i.next();
        if (task.getName().indexOf("muc") > -1)
    break;
        task = null;
      }
        
      for (int i=0; i<10; i++) {
        URI aifuri = URI.create(base.toString()+"tmp/test."+i+".aif.xml");
            
        try {
    URI signal = URI.create(base.toString()+"tmp/test.txt");
    JawbDocument doc = JawbDocument.fromSignal(signal, task,
                                               "text", "UTF-8");
    doc.save(aifuri);
        
    Timer timer = new Timer();
    timer.start();
    try { Thread.sleep(200); } catch (Exception e) {}
    timer.pause(true);
        
    logger.updateLog(doc,timer);
        
    doc.close();
        } catch (Exception e){
    System.err.println ("Error logging: "+e.getMessage());
    e.printStackTrace();
        }
      }
        
      System.exit(0);
    }
    */
}