2442d10d4f19a84e6c3ae8237dbf7bdc9999d920
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.lami.core / src / org / eclipse / tracecompass / internal / provisional / analysis / lami / core / types / LamiData.java
1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 EfficiOS Inc. and others
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9
10 package org.eclipse.tracecompass.internal.provisional.analysis.lami.core.types;
11
12 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
13
14 import java.util.Map;
15 import java.util.function.Function;
16
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.LamiStrings;
19 import org.json.JSONException;
20 import org.json.JSONObject;
21
22 import com.google.common.collect.ImmutableMap;
23
24 /**
25 * Base class for data types allowed in LAMI analysis scripts JSON output.
26 *
27 * @author Alexandre Montplaisir
28 * @author Philippe Proulx
29 */
30 public abstract class LamiData {
31
32 /**
33 * Enum of all the valid data types
34 */
35 @SuppressWarnings("javadoc")
36 public enum DataType {
37
38 /* Generic JSON types */
39 STRING("string", "Value", false, null, LamiString.class), //$NON-NLS-1$ //$NON-NLS-2$
40 INT("int", "Value", true, null, LamiInteger.class), //$NON-NLS-1$ //$NON-NLS-2$
41 FLOAT("float", "Value", true, null, LamiNumber.class), //$NON-NLS-1$ //$NON-NLS-2$
42 NUMBER("number", "Value", true, null, LamiNumber.class), //$NON-NLS-1$ //$NON-NLS-2$
43 BOOL("bool", "Value", false, null, LamiBoolean.class), //$NON-NLS-1$ //$NON-NLS-2$
44
45 /* Lami-specific data types */
46 RATIO("ratio", "Ratio", true, "%", LamiRatio.class), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
47 TIMESTAMP("timestamp", "Timestamp", true, "ns", LamiTimestamp.class), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
48 TIME_RANGE("time-range", "Time range", true, null, LamiTimeRange.class), //$NON-NLS-1$ //$NON-NLS-2$
49 DURATION("duration", "Duration", true, "ns", LamiDuration.class), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
50 SIZE("size", "Size", true, Messages.LamiData_UnitBytes, LamiSize.class), //$NON-NLS-1$ //$NON-NLS-2$
51 BITRATE("bitrate", "Bitrate", true, Messages.LamiData_UnitBitsPerSecond, LamiBitrate.class), //$NON-NLS-1$ //$NON-NLS-2$
52 SYSCALL("syscall", "System call", false, null, LamiSystemCall.class), //$NON-NLS-1$ //$NON-NLS-2$
53 PROCESS("process", "Process", false, null, LamiProcess.class), //$NON-NLS-1$ //$NON-NLS-2$
54 PATH("path", "Path", false, null, LamiPath.class), //$NON-NLS-1$ //$NON-NLS-2$
55 FD("fd", "File descriptor", false, null, LamiFileDescriptor.class), //$NON-NLS-1$ //$NON-NLS-2$
56 IRQ("irq", "IRQ", false, null, LamiIRQ.class), //$NON-NLS-1$ //$NON-NLS-2$
57 CPU("cpu", "CPU", false, null, LamiCPU.class), //$NON-NLS-1$ //$NON-NLS-2$
58 DISK("disk", "Disk", false, null, LamiDisk.class), //$NON-NLS-1$ //$NON-NLS-2$
59 PART("part", "Disk partition", false, null, LamiDiskPartition.class), //$NON-NLS-1$ //$NON-NLS-2$
60 NETIF("netif", "Network interface", false, null, LamiNetworkInterface.class), //$NON-NLS-1$ //$NON-NLS-2$
61 UNKNOWN("unknown", "Value", false, null, LamiUnknown.class), //$NON-NLS-1$ //$NON-NLS-2$
62 MIXED("mixed", "Value", false, null, null); //$NON-NLS-1$ //$NON-NLS-2$
63
64 private final String fName;
65 private final String fTitle;
66 private final boolean fIsContinuous;
67 private final @Nullable String fUnits;
68 private final @Nullable Class<?> fClass;
69
70 private DataType(String name, String title, boolean isContinous, @Nullable String units, @Nullable Class<?> cls) {
71 fName = name;
72 fTitle = title;
73 fIsContinuous = isContinous;
74 fUnits = units;
75 fClass = cls;
76 }
77
78 /**
79 * Indicates if this data type represents a continuous numerical value.
80 *
81 * For example, time or bitrates are continuous values, but CPU or IRQ
82 * numbers are not (you can't have CPU 1.5!)
83 *
84 * @return If this aspect is continuous
85 */
86 public boolean isContinuous() {
87 return fIsContinuous;
88 }
89
90 /**
91 * Get the units of this data type, if any.
92 *
93 * @return The units, or <code>null</code> if there are no units
94 */
95 public @Nullable String getUnits() {
96 return fUnits;
97 }
98
99 /**
100 * The default title for columns containing these units.
101 *
102 * @return The data type's column title
103 */
104 public String getTitle() {
105 return fTitle;
106 }
107
108 /**
109 * Get the data type from its JSON string representation.
110 *
111 * @param value
112 * The string
113 * @return The corresponding data type
114 */
115 public static DataType fromString(String value) {
116 for (DataType type : DataType.values()) {
117 if (type.fName.equals(value)) {
118 return type;
119 }
120 }
121 throw new IllegalArgumentException("Unrecognized type: " + value);
122 }
123
124 /**
125 * Get the date type enum element from its implementation Class.
126 *
127 * @param cls
128 * The data type class
129 * @return The data type
130 */
131 public static @Nullable DataType fromClass(Class<? extends LamiData> cls) {
132 for (DataType type : DataType.values()) {
133 if (cls.equals(type.fClass)) {
134 return type;
135 }
136 }
137
138 return null;
139 }
140 }
141
142 @Override
143 public abstract @Nullable String toString();
144
145 // ------------------------------------------------------------------------
146 // Convenience methods
147 // ------------------------------------------------------------------------
148
149 /**
150 * Convenience method to get the "value" field from a JSON object. Many LAMI
151 * types have a "value" field.
152 *
153 * @param obj
154 * The JSON object
155 * @return The read value
156 * @throws JSONException
157 * If the object does not actually have a "value" field.
158 */
159 private static final long getJSONObjectLongValue(JSONObject obj) throws JSONException {
160 return obj.getLong(LamiStrings.VALUE);
161 }
162
163 /**
164 * Convenience method to get the "name" field from a JSON object. Many LAMI
165 * types have a "nam" field.
166 *
167 * @param obj
168 * The JSON object
169 * @return The read name
170 * @throws JSONException
171 * If the object does not actually have a "name" field.
172 */
173 private static final String getJSONObjectStringName(JSONObject obj) throws JSONException {
174 return checkNotNull(obj.getString(LamiStrings.NAME));
175 }
176
177 // ------------------------------------------------------------------------
178 // "Factory" methods and helpers
179 // ------------------------------------------------------------------------
180
181 /**
182 * Factory method to build a new LamiData object from either a
183 * {@link JSONObject} or a standard Java {@link Object} representing a
184 * primitive type.
185 *
186 * @param obj
187 * The source object
188 * @return The corresponding LamiData object
189 * @throws JSONException
190 * If the object type is not supported
191 */
192 public static LamiData createFromObject(Object obj) throws JSONException {
193 if (obj instanceof JSONObject) {
194 return createFromJsonObject((JSONObject) obj);
195 } else if (obj.equals(JSONObject.NULL)) {
196 return LamiEmpty.INSTANCE;
197 } else {
198 return createFromPrimitiveObject(obj);
199 }
200 }
201
202 @FunctionalInterface
203 private static interface CheckedJSONExceptionFunction<T, R> {
204 R apply(T t) throws JSONException;
205 }
206
207 /**
208 * Map returning the Functions to build new LAMI objects for JSON primitive
209 * types
210 */
211 private static final Map<Class<?>, Function<Object, LamiData>> PRIMITIVE_TYPE_GENERATOR;
212 static {
213 ImmutableMap.Builder<Class<?>, Function<Object, LamiData>> primitiveTypeGenBuilder = ImmutableMap.builder();
214 primitiveTypeGenBuilder.put(Boolean.class, (o) -> LamiBoolean.instance((Boolean) o));
215 primitiveTypeGenBuilder.put(Integer.class, (o) -> new LamiInteger(((Integer) o).longValue()));
216 primitiveTypeGenBuilder.put(Long.class, (o) -> new LamiInteger((Long) o));
217 primitiveTypeGenBuilder.put(Double.class, (o) -> new LamiNumber((Double) o));
218 primitiveTypeGenBuilder.put(String.class, (o) -> new LamiString((String) o));
219 PRIMITIVE_TYPE_GENERATOR = primitiveTypeGenBuilder.build();
220 }
221
222 /**
223 * Map returning the Functions to build new LAMI objects for LAMI-specific
224 * types
225 */
226 private static final Map<String, CheckedJSONExceptionFunction<JSONObject, LamiData>> COMPLEX_TYPE_GENERATOR;
227 static {
228 ImmutableMap.Builder<String, CheckedJSONExceptionFunction<JSONObject, LamiData>> complexTypeGenBuilder = ImmutableMap.builder();
229 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_BITRATE, (obj) -> new LamiBitrate(getJSONObjectLongValue(obj)));
230 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_CPU, (obj) -> new LamiCPU(obj.getLong(LamiStrings.ID)));
231 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_DISK, (obj) -> new LamiDisk(getJSONObjectStringName(obj)));
232 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_DURATION, (obj) -> new LamiDuration(getJSONObjectLongValue(obj)));
233 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_PART, (obj) -> new LamiDiskPartition(getJSONObjectStringName(obj)));
234 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_FD, (obj) -> new LamiFileDescriptor(obj.getLong(LamiStrings.FD)));
235 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_NETIF, (obj) -> new LamiNetworkInterface(getJSONObjectStringName(obj)));
236 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_PATH, (obj) -> new LamiPath(checkNotNull(obj.getString(LamiStrings.PATH))));
237 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_PROCESS, (obj) -> {
238 String name = obj.optString(LamiStrings.NAME);
239 Long pid = (obj.has(LamiStrings.PID) ? obj.getLong(LamiStrings.PID) : null);
240 Long tid = (obj.has(LamiStrings.TID) ? obj.getLong(LamiStrings.TID) : null);
241
242 return new LamiProcess(name, pid, tid);
243 });
244 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_RATIO, (obj) -> new LamiRatio(obj.getDouble(LamiStrings.VALUE)));
245 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_IRQ, (obj) -> {
246 LamiIRQ.Type irqType = LamiIRQ.Type.HARD;
247
248 if (obj.has(LamiStrings.HARD)) {
249 boolean isHardIrq = obj.getBoolean(LamiStrings.HARD);
250 irqType = (isHardIrq ? LamiIRQ.Type.HARD : LamiIRQ.Type.SOFT);
251 }
252
253 int nr = obj.getInt(LamiStrings.NR);
254 String name = obj.optString(LamiStrings.NAME);
255
256 return new LamiIRQ(irqType, nr, name);
257 });
258 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_SIZE, (obj) -> new LamiSize(getJSONObjectLongValue(obj)));
259 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_SYSCALL, (obj) -> new LamiSystemCall(getJSONObjectStringName(obj)));
260 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_TIME_RANGE, (obj) -> {
261 long begin = obj.getLong(LamiStrings.BEGIN);
262 long end = obj.getLong(LamiStrings.END);
263
264 return new LamiTimeRange(begin, end);
265 });
266 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_TIMESTAMP, (obj) -> new LamiTimestamp(getJSONObjectLongValue(obj)));
267 complexTypeGenBuilder.put(LamiStrings.DATA_CLASS_UNKNOWN, (obj) -> LamiUnknown.INSTANCE);
268 COMPLEX_TYPE_GENERATOR = complexTypeGenBuilder.build();
269 }
270
271 /**
272 * Create a new LamiData for a primitive type (Integer, String, etc.)
273 *
274 * @param obj
275 * The source object
276 * @return A new corresponding LamiData object
277 * @throws JSONException
278 * If the object type is not supported
279 */
280 private static LamiData createFromPrimitiveObject(Object obj) throws JSONException {
281 Function<Object, LamiData> func = PRIMITIVE_TYPE_GENERATOR.get(obj.getClass());
282 if (func == null) {
283 throw new JSONException("Unhandled type: " + obj.toString() + " of type " + obj.getClass().toString()); //$NON-NLS-1$ //$NON-NLS-2$
284 }
285 /* We never return null in the implementations */
286 return checkNotNull(func.apply(obj));
287 }
288
289 /**
290 * Create a new LamiData for a LAMI-specific type from a {@link JSONObject}.
291 *
292 * @param obj
293 * The source object
294 * @return A new corresponding LamiData object
295 * @throws JSONException
296 * If the object type is not supported
297 */
298 private static LamiData createFromJsonObject(JSONObject obj) throws JSONException {
299 String dataClass = obj.optString(LamiStrings.CLASS);
300
301 if (dataClass == null) {
302 throw new JSONException("Cannot find data class"); //$NON-NLS-1$
303 }
304
305 CheckedJSONExceptionFunction<JSONObject, LamiData> func = COMPLEX_TYPE_GENERATOR.get(dataClass);
306
307 if (func == null) {
308 throw new JSONException(String.format("Unsupported data class \"%s\"", dataClass)); //$NON-NLS-1$
309 }
310
311 return func.apply(obj);
312 }
313 }
This page took 0.037632 seconds and 4 git commands to generate.