• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 
17 package com.android.ddmlib.log;
18 
19 import com.android.ddmlib.log.LogReceiver.LogEntry;
20 
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23 
24 /**
25  * Represents an event and its data.
26  */
27 public class EventContainer {
28 
29     /**
30      * Comparison method for {@link EventContainer#testValue(int, Object, com.android.ddmlib.log.EventContainer.CompareMethod)}
31      *
32      */
33     public enum CompareMethod {
34         EQUAL_TO("equals", "=="),
35         LESSER_THAN("less than or equals to", "<="),
36         LESSER_THAN_STRICT("less than", "<"),
37         GREATER_THAN("greater than or equals to", ">="),
38         GREATER_THAN_STRICT("greater than", ">"),
39         BIT_CHECK("bit check", "&");
40 
41         private final String mName;
42         private final String mTestString;
43 
CompareMethod(String name, String testString)44         private CompareMethod(String name, String testString) {
45             mName = name;
46             mTestString = testString;
47         }
48 
49         /**
50          * Returns the display string.
51          */
52         @Override
toString()53         public String toString() {
54             return mName;
55         }
56 
57         /**
58          * Returns a short string representing the comparison.
59          */
testString()60         public String testString() {
61             return mTestString;
62         }
63     }
64 
65 
66     /**
67      * Type for event data.
68      */
69     public static enum EventValueType {
70         UNKNOWN(0),
71         INT(1),
72         LONG(2),
73         STRING(3),
74         LIST(4),
75         TREE(5);
76 
77         private final static Pattern STORAGE_PATTERN = Pattern.compile("^(\\d+)@(.*)$"); //$NON-NLS-1$
78 
79         private int mValue;
80 
81         /**
82          * Returns a {@link EventValueType} from an integer value, or <code>null</code> if no match
83          * was found.
84          * @param value the integer value.
85          */
getEventValueType(int value)86         static EventValueType getEventValueType(int value) {
87             for (EventValueType type : values()) {
88                 if (type.mValue == value) {
89                     return type;
90                 }
91             }
92 
93             return null;
94         }
95 
96         /**
97          * Returns a storage string for an {@link Object} of type supported by
98          * {@link EventValueType}.
99          * <p/>
100          * Strings created by this method can be reloaded with
101          * {@link #getObjectFromStorageString(String)}.
102          * <p/>
103          * NOTE: for now, only {@link #STRING}, {@link #INT}, and {@link #LONG} are supported.
104          * @param object the object to "convert" into a storage string.
105          * @return a string storing the object and its type or null if the type was not recognized.
106          */
getStorageString(Object object)107         public static String getStorageString(Object object) {
108             if (object instanceof String) {
109                 return STRING.mValue + "@" + (String)object; //$NON-NLS-1$
110             } else if (object instanceof Integer) {
111                 return INT.mValue + "@" + object.toString(); //$NON-NLS-1$
112             } else if (object instanceof Long) {
113                 return LONG.mValue + "@" + object.toString(); //$NON-NLS-1$
114             }
115 
116             return null;
117         }
118 
119         /**
120          * Creates an {@link Object} from a storage string created with
121          * {@link #getStorageString(Object)}.
122          * @param value the storage string
123          * @return an {@link Object} or null if the string or type were not recognized.
124          */
getObjectFromStorageString(String value)125         public static Object getObjectFromStorageString(String value) {
126             Matcher m = STORAGE_PATTERN.matcher(value);
127             if (m.matches()) {
128                 try {
129                     EventValueType type = getEventValueType(Integer.parseInt(m.group(1)));
130 
131                     if (type == null) {
132                         return null;
133                     }
134 
135                     switch (type) {
136                         case STRING:
137                             return m.group(2);
138                         case INT:
139                             return Integer.valueOf(m.group(2));
140                         case LONG:
141                             return Long.valueOf(m.group(2));
142                     }
143                 } catch (NumberFormatException nfe) {
144                     return null;
145                 }
146             }
147 
148             return null;
149         }
150 
151 
152         /**
153          * Returns the integer value of the enum.
154          */
getValue()155         public int getValue() {
156             return mValue;
157         }
158 
159         @Override
toString()160         public String toString() {
161             return super.toString().toLowerCase();
162         }
163 
EventValueType(int value)164         private EventValueType(int value) {
165             mValue = value;
166         }
167     }
168 
169     public int mTag;
170     public int pid;    /* generating process's pid */
171     public int tid;    /* generating process's tid */
172     public int sec;    /* seconds since Epoch */
173     public int nsec;   /* nanoseconds */
174 
175     private Object mData;
176 
177     /**
178      * Creates an {@link EventContainer} from a {@link LogEntry}.
179      * @param entry  the LogEntry from which pid, tid, and time info is copied.
180      * @param tag the event tag value
181      * @param data the data of the EventContainer.
182      */
EventContainer(LogEntry entry, int tag, Object data)183     EventContainer(LogEntry entry, int tag, Object data) {
184         getType(data);
185         mTag = tag;
186         mData = data;
187 
188         pid = entry.pid;
189         tid = entry.tid;
190         sec = entry.sec;
191         nsec = entry.nsec;
192     }
193 
194     /**
195      * Creates an {@link EventContainer} with raw data
196      */
EventContainer(int tag, int pid, int tid, int sec, int nsec, Object data)197     EventContainer(int tag, int pid, int tid, int sec, int nsec, Object data) {
198         getType(data);
199         mTag = tag;
200         mData = data;
201 
202         this.pid = pid;
203         this.tid = tid;
204         this.sec = sec;
205         this.nsec = nsec;
206     }
207 
208     /**
209      * Returns the data as an int.
210      * @throws InvalidTypeException if the data type is not {@link EventValueType#INT}.
211      * @see #getType()
212      */
getInt()213     public final Integer getInt() throws InvalidTypeException {
214         if (getType(mData) == EventValueType.INT) {
215             return (Integer)mData;
216         }
217 
218         throw new InvalidTypeException();
219     }
220 
221     /**
222      * Returns the data as a long.
223      * @throws InvalidTypeException if the data type is not {@link EventValueType#LONG}.
224      * @see #getType()
225      */
getLong()226     public final Long getLong() throws InvalidTypeException {
227         if (getType(mData) == EventValueType.LONG) {
228             return (Long)mData;
229         }
230 
231         throw new InvalidTypeException();
232     }
233 
234     /**
235      * Returns the data as a String.
236      * @throws InvalidTypeException if the data type is not {@link EventValueType#STRING}.
237      * @see #getType()
238      */
getString()239     public final String getString() throws InvalidTypeException {
240         if (getType(mData) == EventValueType.STRING) {
241             return (String)mData;
242         }
243 
244         throw new InvalidTypeException();
245     }
246 
247     /**
248      * Returns a value by index. The return type is defined by its type.
249      * @param valueIndex the index of the value. If the data is not a list, this is ignored.
250      */
getValue(int valueIndex)251     public Object getValue(int valueIndex) {
252         return getValue(mData, valueIndex, true);
253     }
254 
255     /**
256      * Returns a value by index as a double.
257      * @param valueIndex the index of the value. If the data is not a list, this is ignored.
258      * @throws InvalidTypeException if the data type is not {@link EventValueType#INT},
259      * {@link EventValueType#LONG}, {@link EventValueType#LIST}, or if the item in the
260      * list at index <code>valueIndex</code> is not of type {@link EventValueType#INT} or
261      * {@link EventValueType#LONG}.
262      * @see #getType()
263      */
getValueAsDouble(int valueIndex)264     public double getValueAsDouble(int valueIndex) throws InvalidTypeException {
265         return getValueAsDouble(mData, valueIndex, true);
266     }
267 
268     /**
269      * Returns a value by index as a String.
270      * @param valueIndex the index of the value. If the data is not a list, this is ignored.
271      * @throws InvalidTypeException if the data type is not {@link EventValueType#INT},
272      * {@link EventValueType#LONG}, {@link EventValueType#STRING}, {@link EventValueType#LIST},
273      * or if the item in the list at index <code>valueIndex</code> is not of type
274      * {@link EventValueType#INT}, {@link EventValueType#LONG}, or {@link EventValueType#STRING}
275      * @see #getType()
276      */
getValueAsString(int valueIndex)277     public String getValueAsString(int valueIndex) throws InvalidTypeException {
278         return getValueAsString(mData, valueIndex, true);
279     }
280 
281     /**
282      * Returns the type of the data.
283      */
getType()284     public EventValueType getType() {
285         return getType(mData);
286     }
287 
288     /**
289      * Returns the type of an object.
290      */
getType(Object data)291     public final EventValueType getType(Object data) {
292         if (data instanceof Integer) {
293             return EventValueType.INT;
294         } else if (data instanceof Long) {
295             return EventValueType.LONG;
296         } else if (data instanceof String) {
297             return EventValueType.STRING;
298         } else if (data instanceof Object[]) {
299             // loop through the list to see if we have another list
300             Object[] objects = (Object[])data;
301             for (Object obj : objects) {
302                 EventValueType type = getType(obj);
303                 if (type == EventValueType.LIST || type == EventValueType.TREE) {
304                     return EventValueType.TREE;
305                 }
306             }
307             return EventValueType.LIST;
308         }
309 
310         return EventValueType.UNKNOWN;
311     }
312 
313     /**
314      * Checks that the <code>index</code>-th value of this event against a provided value.
315      * @param index the index of the value to test
316      * @param value the value to test against
317      * @param compareMethod the method of testing
318      * @return true if the test passed.
319      * @throws InvalidTypeException in case of type mismatch between the value to test and the value
320      * to test against, or if the compare method is incompatible with the type of the values.
321      * @see CompareMethod
322      */
testValue(int index, Object value, CompareMethod compareMethod)323     public boolean testValue(int index, Object value,
324             CompareMethod compareMethod) throws InvalidTypeException {
325         EventValueType type = getType(mData);
326         if (index > 0 && type != EventValueType.LIST) {
327             throw new InvalidTypeException();
328         }
329 
330         Object data = mData;
331         if (type == EventValueType.LIST) {
332             data = ((Object[])mData)[index];
333         }
334 
335         if (data.getClass().equals(data.getClass()) == false) {
336             throw new InvalidTypeException();
337         }
338 
339         switch (compareMethod) {
340             case EQUAL_TO:
341                 return data.equals(value);
342             case LESSER_THAN:
343                 if (data instanceof Integer) {
344                     return (((Integer)data).compareTo((Integer)value) <= 0);
345                 } else if (data instanceof Long) {
346                     return (((Long)data).compareTo((Long)value) <= 0);
347                 }
348 
349                 // other types can't use this compare method.
350                 throw new InvalidTypeException();
351             case LESSER_THAN_STRICT:
352                 if (data instanceof Integer) {
353                     return (((Integer)data).compareTo((Integer)value) < 0);
354                 } else if (data instanceof Long) {
355                     return (((Long)data).compareTo((Long)value) < 0);
356                 }
357 
358                 // other types can't use this compare method.
359                 throw new InvalidTypeException();
360             case GREATER_THAN:
361                 if (data instanceof Integer) {
362                     return (((Integer)data).compareTo((Integer)value) >= 0);
363                 } else if (data instanceof Long) {
364                     return (((Long)data).compareTo((Long)value) >= 0);
365                 }
366 
367                 // other types can't use this compare method.
368                 throw new InvalidTypeException();
369             case GREATER_THAN_STRICT:
370                 if (data instanceof Integer) {
371                     return (((Integer)data).compareTo((Integer)value) > 0);
372                 } else if (data instanceof Long) {
373                     return (((Long)data).compareTo((Long)value) > 0);
374                 }
375 
376                 // other types can't use this compare method.
377                 throw new InvalidTypeException();
378             case BIT_CHECK:
379                 if (data instanceof Integer) {
380                     return (((Integer)data).intValue() & ((Integer)value).intValue()) != 0;
381                 } else if (data instanceof Long) {
382                     return (((Long)data).longValue() & ((Long)value).longValue()) != 0;
383                 }
384 
385                 // other types can't use this compare method.
386                 throw new InvalidTypeException();
387             default :
388                 throw new InvalidTypeException();
389         }
390     }
391 
getValue(Object data, int valueIndex, boolean recursive)392     private final Object getValue(Object data, int valueIndex, boolean recursive) {
393         EventValueType type = getType(data);
394 
395         switch (type) {
396             case INT:
397             case LONG:
398             case STRING:
399                 return data;
400             case LIST:
401                 if (recursive) {
402                     Object[] list = (Object[]) data;
403                     if (valueIndex >= 0 && valueIndex < list.length) {
404                         return getValue(list[valueIndex], valueIndex, false);
405                     }
406                 }
407         }
408 
409         return null;
410     }
411 
getValueAsDouble(Object data, int valueIndex, boolean recursive)412     private final double getValueAsDouble(Object data, int valueIndex, boolean recursive)
413             throws InvalidTypeException {
414         EventValueType type = getType(data);
415 
416         switch (type) {
417             case INT:
418                 return ((Integer)data).doubleValue();
419             case LONG:
420                 return ((Long)data).doubleValue();
421             case STRING:
422                 throw new InvalidTypeException();
423             case LIST:
424                 if (recursive) {
425                     Object[] list = (Object[]) data;
426                     if (valueIndex >= 0 && valueIndex < list.length) {
427                         return getValueAsDouble(list[valueIndex], valueIndex, false);
428                     }
429                 }
430         }
431 
432         throw new InvalidTypeException();
433     }
434 
getValueAsString(Object data, int valueIndex, boolean recursive)435     private final String getValueAsString(Object data, int valueIndex, boolean recursive)
436             throws InvalidTypeException {
437         EventValueType type = getType(data);
438 
439         switch (type) {
440             case INT:
441                 return ((Integer)data).toString();
442             case LONG:
443                 return ((Long)data).toString();
444             case STRING:
445                 return (String)data;
446             case LIST:
447                 if (recursive) {
448                     Object[] list = (Object[]) data;
449                     if (valueIndex >= 0 && valueIndex < list.length) {
450                         return getValueAsString(list[valueIndex], valueIndex, false);
451                     }
452                 } else {
453                     throw new InvalidTypeException(
454                             "getValueAsString() doesn't support EventValueType.TREE");
455                 }
456         }
457 
458         throw new InvalidTypeException(
459                 "getValueAsString() unsupported type:" + type);
460     }
461 }
462