com.google.research.ic.ferret.data.ext.alogger.AccessibilityLogParser.java Source code

Java tutorial

Introduction

Here is the source code for com.google.research.ic.ferret.data.ext.alogger.AccessibilityLogParser.java

Source

/*******************************************************************************
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.google.research.ic.ferret.data.ext.alogger;

import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.research.ic.ferret.data.Event;
import com.google.research.ic.ferret.data.LogLoader;
import com.google.research.ic.ferret.data.Parser;
import com.google.research.ic.ferret.data.Snippet;
import com.google.research.ic.ferret.data.attributes.Attribute;
import com.google.research.ic.ferret.test.Debug;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A class to read in event logs and create a searchable data structure 
 * (generated by marknewman)
 */
public class AccessibilityLogParser implements Parser {

    public static final String DEFAULT_LOG_DIRECTORY = "logs"; //assume cwd/logs
    public static final String DEFAULT_DEMO_DIRECTORY = DEFAULT_LOG_DIRECTORY + File.separator + "demos";

    static int removed = 0;

    Gson gson = new Gson();
    private static AccessibilityLogParser theParser = null;

    private AccessibilityLogParser() {
    }

    public static AccessibilityLogParser getParser() {
        if (theParser == null) {
            theParser = new AccessibilityLogParser();
        }
        return theParser;
    }

    @Override
    public List<Snippet> readLogDirectory(String logDirName) {

        if (logDirName == null) {
            logDirName = DEFAULT_LOG_DIRECTORY;
        }

        ArrayList<Snippet> snippets = new ArrayList<Snippet>();

        File logDir = new File(System.getProperty("user.dir"), logDirName);
        FileFilter filter = new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.getName().endsWith(".txt") || file.getName().endsWith(".log")
                        || file.getName().endsWith(".json"));
            }
        };
        File[] logFiles = logDir.listFiles(filter);
        for (int i = 0; i < logFiles.length; i++) {
            File logFile = logFiles[i];
            snippets.addAll(readLogFile(logFile));
        }
        return snippets;
    }

    public List<Snippet> readLogFile(String logFileName) {
        return readLogFile(new File(logFileName));
    }

    public List<Snippet> readLogFile(File logFile) {
        HashMap<String, ArrayList<AccessibilityLogEvent>> tmp = new HashMap<String, ArrayList<AccessibilityLogEvent>>();
        int added = 0;
        int skipped = 0;
        String line = null;
        try {
            FileReader fr = new FileReader(logFile);
            BufferedReader br = new BufferedReader(fr);
            line = null;
            while ((line = br.readLine()) != null) {
                AccessibilityLogEvent alE = null;
                try {
                    alE = eventFromGsonString(line.trim());
                } catch (Exception e) {
                    System.err.println("Choked on line, ignoring: " + line);
                    System.err.println(e.getMessage());
                }
                //System.out.println("Did fine on line " + line);
                if (alE == null)
                    continue;
                alE.init(); //TODO: create JSONDeserializer for this? Kinda ugly either way.
                if (alE.isSkippable()) {
                    skipped++;
                    continue;
                }
                ArrayList<AccessibilityLogEvent> list = tmp.get(alE.getUserId());
                if (list == null) {
                    list = new ArrayList<AccessibilityLogEvent>();
                    tmp.put(alE.getUserId(), list);
                }
                list.add(alE);
                added++;
            }
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        List<Snippet> snippets = new ArrayList<Snippet>();
        for (Map.Entry<String, ArrayList<AccessibilityLogEvent>> entry : tmp.entrySet()) {
            Collections.sort(entry.getValue());
            Snippet snippet = new Snippet();
            for (AccessibilityLogEvent alE : entry.getValue()) {
                snippet.addEvent(alE);
                compressSnippet(snippet, false);
            }
            snippet.setSourceFilename(logFile.getName());
            snippets.add(snippet);
        }
        Debug.log(added + " events added for " + tmp.size() + " users [" + skipped + " events skipped]");
        return snippets;

    }

    @Override
    public List<Snippet> readDemoDirectory(String demoDirName) {
        if (demoDirName == null) {
            demoDirName = DEFAULT_DEMO_DIRECTORY;
        }
        return readLogDirectory(demoDirName);

    }

    @Override
    public AccessibilityLogEvent parseEvent(String eventString) {

        try {
            //Debug.log("parsing event string : " + eventString);
            AccessibilityLogEvent e = eventFromGsonString(eventString);
            if (e.isSkippable()) {
                return null;
            }
            return e;
        } catch (Exception e) {
            // wasn't a gson string, so not sure what to do
            Debug.log("Unhandled exception in parseEvent: " + e);
        }
        return null;
    }

    /**
     * @param gsonString
     * @return event
     */
    public AccessibilityLogEvent eventFromGsonString(String gsonString) {
        AccessibilityLogEvent alE = gson.fromJson(gsonString, AccessibilityLogEvent.class);
        alE.init();
        alE.setIdentifierId(LogLoader.getLogLoader().getOrCreateIdentifierId(alE.getIdentifier()));
        return alE;
    }

    @Override
    public Event deserializeEvent(JsonElement json, Type klass, JsonDeserializationContext jdContext) {
        return jdContext.deserialize(json, AccessibilityLogEvent.class);
    }

    @Override
    public List<Attribute> getAvailableAttributes() {
        List<Attribute> attributes = new ArrayList<Attribute>();
        //     attributes.add(OLDAttribute.GENERIC_ATTRIBUTE_USER_NAME);
        //     attributes.add(OLDAttribute.GENERIC_ATTRIBUTE_START_TIME);
        //     attributes.add(OLDAttribute.GENERIC_ATTRIBUTE_DURATION);

        return attributes;

    }

    public boolean compressSnippet(Snippet snippet, boolean inspectWholeSnippet) {

        if (inspectWholeSnippet) {
            throw new UnsupportedOperationException("inspectWholeSnippet not yet implemented");
        }

        // look at the end of the snippet.
        // if it's a TEXT_CHANGED or TEXT_SELECTION_CHANGED event...
        // and the previous event is one of those...
        // and the event sources (widgets) are the same...
        // remove this event
        int size = snippet.getEvents().size();
        if (size < 2)
            return false;

        AccessibilityLogEvent lastEvent = (AccessibilityLogEvent) snippet.getEvents().get(size - 1);
        AccessibilityLogEvent prevEvent = (AccessibilityLogEvent) snippet.getEvents().get(size - 2);

        if (lastEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_TEXT_CHANGED) {
            if (prevEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_TEXT_CHANGED) {
                snippet.getEvents().remove(size - 2);
                return true;
            }
        } else if (lastEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED) {
            if (prevEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_TEXT_CHANGED) {
                if (hasSameSource(lastEvent, prevEvent)) {
                    snippet.getEvents().remove(size - 1);
                    return true;
                }
            }
        } else if (lastEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_SCROLLED) {
            if (prevEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_SCROLLED) {
                if (!hasSameSource(lastEvent, prevEvent))
                    return false;
                snippet.getEvents().remove(size - 1);
                prevEvent.addRepetition();
                return true;
            } else if (prevEvent.getEventType() == AccessibilityLogEvent.TYPE_VIEW_TEXT_CHANGED) {
                // a scroll event right after text changed is probably triggered by it, and probably noise
                snippet.getEvents().remove(size - 1);
                return true;
            }
        }
        return false;
    }

    private boolean hasSameSource(AccessibilityLogEvent e1, AccessibilityLogEvent e2) {
        if (e1.getPathToRoot() != null) {
            if (e2.getPathToRoot() == null)
                return false;
            if (!e1.getPathToRoot().equals(e2.getPathToRoot()))
                return false;
        }

        if (!e1.getModuleName().equals(e2.getModuleName()))
            return false;
        if (!e1.getwClassName().equals(e2.getwClassName()))
            return false;
        return true;
    }

    @Override
    public void writeSnippet(Snippet snip, File file) {
        DataOutputStream output = null;
        try {
            output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (Event evt : snip.getEvents()) {
            writeEvent(evt, output);
        }
        try {
            output.flush();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void writeEvent(Event evt, File file) {
        if (file != null) {
            try {
                DataOutputStream output = new DataOutputStream(
                        new BufferedOutputStream(new FileOutputStream(file, true)));
                writeEvent(evt, output);
                output.flush();
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void writeEvent(Event evt, DataOutputStream output) {
        if (!(evt instanceof AccessibilityLogEvent)) {
            throw new IllegalArgumentException("AccessibilityLogParser can't write out event " + evt);
        }
        AccessibilityLogEvent aEvt = (AccessibilityLogEvent) evt;

        if (output != null) {
            try {
                String jsonString = new Gson().toJson(aEvt);
                output.writeBytes(jsonString + "\n");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}