Java tutorial
/******************************************************************************* * 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(); } } } }