1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.loganalysis.item;
17 
18 import org.json.JSONArray;
19 import org.json.JSONException;
20 import org.json.JSONObject;
21 
22 import java.util.Arrays;
23 import java.util.Date;
24 import java.util.HashSet;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Set;
28 
29 /**
30  * An {@link IItem} used to store logcat info.
31  */
32 public class LogcatItem extends GenericItem {
33 
34     /** Constant for JSON output */
35     public static final String START_TIME = "START_TIME";
36     /** Constant for JSON output */
37     public static final String STOP_TIME = "STOP_TIME";
38     /** Constant for JSON output */
39     public static final String EVENTS = "EVENTS";
40 
41     private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
42             START_TIME, STOP_TIME, EVENTS));
43 
44     @SuppressWarnings("serial")
45     private class ItemList extends LinkedList<MiscLogcatItem> {}
46 
47     /**
48      * The constructor for {@link LogcatItem}.
49      */
LogcatItem()50     public LogcatItem() {
51         super(ATTRIBUTES);
52 
53         setAttribute(EVENTS, new ItemList());
54     }
55 
56     /**
57      * Get the start time of the logcat.
58      */
getStartTime()59     public Date getStartTime() {
60         return (Date) getAttribute(START_TIME);
61     }
62 
63     /**
64      * Set the start time of the logcat.
65      */
setStartTime(Date time)66     public void setStartTime(Date time) {
67         setAttribute(START_TIME, time);
68     }
69 
70     /**
71      * Get the stop time of the logcat.
72      */
getStopTime()73     public Date getStopTime() {
74         return (Date) getAttribute(STOP_TIME);
75     }
76 
77     /**
78      * Set the stop time of the logcat.
79      */
setStopTime(Date time)80     public void setStopTime(Date time) {
81         setAttribute(STOP_TIME, time);
82     }
83 
84     /**
85      * Get the list of all {@link MiscLogcatItem} events.
86      */
getEvents()87     public List<MiscLogcatItem> getEvents() {
88         return (ItemList) getAttribute(EVENTS);
89     }
90 
91     /**
92      * Add an {@link MiscLogcatItem} event to the end of the list of events.
93      */
addEvent(MiscLogcatItem event)94     public void addEvent(MiscLogcatItem event) {
95         ((ItemList) getAttribute(EVENTS)).add(event);
96     }
97 
98     /**
99      * Get the list of all {@link AnrItem} events.
100      */
getAnrs()101     public List<AnrItem> getAnrs() {
102         List<AnrItem> anrs = new LinkedList<AnrItem>();
103         for (IItem item : getEvents()) {
104             if (item instanceof AnrItem) {
105                 anrs.add((AnrItem) item);
106             }
107         }
108         return anrs;
109     }
110 
111     /**
112      * Get the list of all {@link JavaCrashItem} events.
113      */
getJavaCrashes()114     public List<JavaCrashItem> getJavaCrashes() {
115         List<JavaCrashItem> jcs = new LinkedList<JavaCrashItem>();
116         for (IItem item : getEvents()) {
117             if (item instanceof JavaCrashItem) {
118                 jcs.add((JavaCrashItem) item);
119             }
120         }
121         return jcs;
122     }
123 
124     /**
125      * Get the list of all {@link NativeCrashItem} events.
126      */
getNativeCrashes()127     public List<NativeCrashItem> getNativeCrashes() {
128         List<NativeCrashItem> ncs = new LinkedList<NativeCrashItem>();
129         for (IItem item : getEvents()) {
130             if (item instanceof NativeCrashItem) {
131                 ncs.add((NativeCrashItem) item);
132             }
133         }
134         return ncs;
135     }
136 
137     /**
138      * Get the list of all {@link MiscLogcatItem} events for a cateogry.
139      */
getMiscEvents(String category)140     public List<MiscLogcatItem> getMiscEvents(String category) {
141         List<MiscLogcatItem> items = new LinkedList<MiscLogcatItem>();
142         for (MiscLogcatItem item : getEvents()) {
143             if (item.getCategory().equals(category)) {
144                 items.add(item);
145             }
146         }
147         return items;
148     }
149 
150     /**
151      * {@inheritDoc}
152      */
153     @Override
merge(IItem other)154     public LogcatItem merge(IItem other) throws ConflictingItemException {
155         if (this == other) {
156             return this;
157         }
158         if (other == null || !(other instanceof LogcatItem)) {
159             throw new ConflictingItemException("Conflicting class types");
160         }
161 
162         LogcatItem logcat = (LogcatItem) other;
163 
164         Date start = logcat.getStartTime().before(getStartTime()) ?
165                 logcat.getStartTime() : getStartTime();
166         Date stop = logcat.getStopTime().after(getStopTime()) ?
167                 logcat.getStopTime() : getStopTime();
168         Date overlapStart = logcat.getStartTime().after(getStartTime()) ?
169                 logcat.getStartTime() : getStartTime();
170         Date overlapStop = logcat.getStopTime().before(getStopTime()) ?
171                 logcat.getStopTime() : getStopTime();
172 
173         // Make sure that all events in the overlapping span are
174         ItemList mergedEvents = new ItemList();
175         for (MiscLogcatItem event : getEvents()) {
176             final Date eventTime = event.getEventTime();
177             if (eventTime.after(overlapStart) && eventTime.before(overlapStop) &&
178                     !logcat.getEvents().contains(event)) {
179                 throw new ConflictingItemException("Event in first logcat not contained in " +
180                         "overlapping portion of other logcat.");
181             }
182             mergedEvents.add(event);
183         }
184 
185         for (MiscLogcatItem event : logcat.getEvents()) {
186             final Date eventTime = event.getEventTime();
187             if (eventTime.after(overlapStart) && eventTime.before(overlapStop)) {
188                 if (!getEvents().contains(event)) {
189                     throw new ConflictingItemException("Event in first logcat not contained in " +
190                             "overlapping portion of other logcat.");
191                 }
192             } else {
193                 mergedEvents.add(event);
194             }
195         }
196 
197         LogcatItem mergedLogcat = new LogcatItem();
198         mergedLogcat.setStartTime(start);
199         mergedLogcat.setStopTime(stop);
200         mergedLogcat.setAttribute(EVENTS, mergedEvents);
201         return mergedLogcat;
202     }
203 
204     /**
205      * {@inheritDoc}
206      */
207     @Override
toJson()208     public JSONObject toJson() {
209         JSONObject output = super.toJson();
210         JSONArray events = new JSONArray();
211         for (MiscLogcatItem event : getEvents()) {
212             events.put(event.toJson());
213         }
214 
215         try {
216             output.put(EVENTS, events);
217         } catch (JSONException e) {
218             // Ignore
219         }
220         return output;
221     }
222 }
223