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