/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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.android.ddmlib.log;
import com.android.ddmlib.log.LogReceiver.LogEntry;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Represents an event and its data.
*/
public class EventContainer {
/**
* Comparison method for {@link EventContainer#testValue(int, Object, com.android.ddmlib.log.EventContainer.CompareMethod)}
*
*/
public enum CompareMethod {
EQUAL_TO("equals", "=="),
LESSER_THAN("less than or equals to", "<="),
LESSER_THAN_STRICT("less than", "<"),
GREATER_THAN("greater than or equals to", ">="),
GREATER_THAN_STRICT("greater than", ">"),
BIT_CHECK("bit check", "&");
private final String mName;
private final String mTestString;
private CompareMethod(String name, String testString) {
mName = name;
mTestString = testString;
}
/**
* Returns the display string.
*/
@Override
public String toString() {
return mName;
}
/**
* Returns a short string representing the comparison.
*/
public String testString() {
return mTestString;
}
}
/**
* Type for event data.
*/
public static enum EventValueType {
UNKNOWN(0),
INT(1),
LONG(2),
STRING(3),
LIST(4),
TREE(5);
private final static Pattern STORAGE_PATTERN = Pattern.compile("^(\\d+)@(.*)$"); //$NON-NLS-1$
private int mValue;
/**
* Returns a {@link EventValueType} from an integer value, or null
if no match
* was found.
* @param value the integer value.
*/
static EventValueType getEventValueType(int value) {
for (EventValueType type : values()) {
if (type.mValue == value) {
return type;
}
}
return null;
}
/**
* Returns a storage string for an {@link Object} of type supported by
* {@link EventValueType}.
*
valueIndex
is not of type {@link EventValueType#INT} or
* {@link EventValueType#LONG}.
* @see #getType()
*/
public double getValueAsDouble(int valueIndex) throws InvalidTypeException {
return getValueAsDouble(mData, valueIndex, true);
}
/**
* Returns a value by index as a String.
* @param valueIndex the index of the value. If the data is not a list, this is ignored.
* @throws InvalidTypeException if the data type is not {@link EventValueType#INT},
* {@link EventValueType#LONG}, {@link EventValueType#STRING}, {@link EventValueType#LIST},
* or if the item in the list at index valueIndex
is not of type
* {@link EventValueType#INT}, {@link EventValueType#LONG}, or {@link EventValueType#STRING}
* @see #getType()
*/
public String getValueAsString(int valueIndex) throws InvalidTypeException {
return getValueAsString(mData, valueIndex, true);
}
/**
* Returns the type of the data.
*/
public EventValueType getType() {
return getType(mData);
}
/**
* Returns the type of an object.
*/
public final EventValueType getType(Object data) {
if (data instanceof Integer) {
return EventValueType.INT;
} else if (data instanceof Long) {
return EventValueType.LONG;
} else if (data instanceof String) {
return EventValueType.STRING;
} else if (data instanceof Object[]) {
// loop through the list to see if we have another list
Object[] objects = (Object[])data;
for (Object obj : objects) {
EventValueType type = getType(obj);
if (type == EventValueType.LIST || type == EventValueType.TREE) {
return EventValueType.TREE;
}
}
return EventValueType.LIST;
}
return EventValueType.UNKNOWN;
}
/**
* Checks that the index
-th value of this event against a provided value.
* @param index the index of the value to test
* @param value the value to test against
* @param compareMethod the method of testing
* @return true if the test passed.
* @throws InvalidTypeException in case of type mismatch between the value to test and the value
* to test against, or if the compare method is incompatible with the type of the values.
* @see CompareMethod
*/
public boolean testValue(int index, Object value,
CompareMethod compareMethod) throws InvalidTypeException {
EventValueType type = getType(mData);
if (index > 0 && type != EventValueType.LIST) {
throw new InvalidTypeException();
}
Object data = mData;
if (type == EventValueType.LIST) {
data = ((Object[])mData)[index];
}
if (data.getClass().equals(data.getClass()) == false) {
throw new InvalidTypeException();
}
switch (compareMethod) {
case EQUAL_TO:
return data.equals(value);
case LESSER_THAN:
if (data instanceof Integer) {
return (((Integer)data).compareTo((Integer)value) <= 0);
} else if (data instanceof Long) {
return (((Long)data).compareTo((Long)value) <= 0);
}
// other types can't use this compare method.
throw new InvalidTypeException();
case LESSER_THAN_STRICT:
if (data instanceof Integer) {
return (((Integer)data).compareTo((Integer)value) < 0);
} else if (data instanceof Long) {
return (((Long)data).compareTo((Long)value) < 0);
}
// other types can't use this compare method.
throw new InvalidTypeException();
case GREATER_THAN:
if (data instanceof Integer) {
return (((Integer)data).compareTo((Integer)value) >= 0);
} else if (data instanceof Long) {
return (((Long)data).compareTo((Long)value) >= 0);
}
// other types can't use this compare method.
throw new InvalidTypeException();
case GREATER_THAN_STRICT:
if (data instanceof Integer) {
return (((Integer)data).compareTo((Integer)value) > 0);
} else if (data instanceof Long) {
return (((Long)data).compareTo((Long)value) > 0);
}
// other types can't use this compare method.
throw new InvalidTypeException();
case BIT_CHECK:
if (data instanceof Integer) {
return (((Integer)data).intValue() & ((Integer)value).intValue()) != 0;
} else if (data instanceof Long) {
return (((Long)data).longValue() & ((Long)value).longValue()) != 0;
}
// other types can't use this compare method.
throw new InvalidTypeException();
default :
throw new InvalidTypeException();
}
}
private final Object getValue(Object data, int valueIndex, boolean recursive) {
EventValueType type = getType(data);
switch (type) {
case INT:
case LONG:
case STRING:
return data;
case LIST:
if (recursive) {
Object[] list = (Object[]) data;
if (valueIndex >= 0 && valueIndex < list.length) {
return getValue(list[valueIndex], valueIndex, false);
}
}
}
return null;
}
private final double getValueAsDouble(Object data, int valueIndex, boolean recursive)
throws InvalidTypeException {
EventValueType type = getType(data);
switch (type) {
case INT:
return ((Integer)data).doubleValue();
case LONG:
return ((Long)data).doubleValue();
case STRING:
throw new InvalidTypeException();
case LIST:
if (recursive) {
Object[] list = (Object[]) data;
if (valueIndex >= 0 && valueIndex < list.length) {
return getValueAsDouble(list[valueIndex], valueIndex, false);
}
}
}
throw new InvalidTypeException();
}
private final String getValueAsString(Object data, int valueIndex, boolean recursive)
throws InvalidTypeException {
EventValueType type = getType(data);
switch (type) {
case INT:
return ((Integer)data).toString();
case LONG:
return ((Long)data).toString();
case STRING:
return (String)data;
case LIST:
if (recursive) {
Object[] list = (Object[]) data;
if (valueIndex >= 0 && valueIndex < list.length) {
return getValueAsString(list[valueIndex], valueIndex, false);
}
} else {
throw new InvalidTypeException(
"getValueAsString() doesn't support EventValueType.TREE");
}
}
throw new InvalidTypeException(
"getValueAsString() unsupported type:" + type);
}
}