Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
97de0bca | 2 | * Copyright (c) 2009, 2015 Ericsson |
306dc902 | 3 | * |
cbbcc354 | 4 | * All rights reserved. This program and the accompanying materials are made |
5 | * available under the terms of the Eclipse Public License v1.0 which | |
8c8bf09f ASL |
6 | * accompanies this distribution, and is available at |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
306dc902 | 8 | * |
8c8bf09f | 9 | * Contributors: |
1f506a43 | 10 | * Francois Chouinard - Initial API and implementation |
bbc1c411 | 11 | * Francois Chouinard - Updated as per TMF Event Model 1.0 |
80349bf7 | 12 | * Alexandre Montplaisir - Removed Cloneable, made immutable |
97de0bca | 13 | * Patrick Tasse - Remove getSubField |
8c8bf09f ASL |
14 | *******************************************************************************/ |
15 | ||
2bdf0193 | 16 | package org.eclipse.tracecompass.tmf.core.event; |
8c8bf09f | 17 | |
5db5a3a4 AM |
18 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
19 | ||
4c4e2816 | 20 | import java.util.Arrays; |
b742c196 | 21 | import java.util.Collection; |
5db5a3a4 | 22 | import java.util.Map; |
b742c196 AM |
23 | |
24 | import org.eclipse.jdt.annotation.NonNull; | |
25 | import org.eclipse.jdt.annotation.Nullable; | |
ac2ae0d8 AM |
26 | import org.eclipse.tracecompass.common.core.NonNullUtils; |
27 | import org.eclipse.tracecompass.common.core.ObjectUtils; | |
b742c196 AM |
28 | |
29 | import com.google.common.base.Joiner; | |
30 | import com.google.common.collect.ImmutableMap; | |
4c564a2d | 31 | |
8c8bf09f | 32 | /** |
b9e37ffd | 33 | * A basic implementation of ITmfEventField. |
8c8bf09f | 34 | * <p> |
b9e37ffd FC |
35 | * Non-value fields are structural (i.e. used to represent the event structure |
36 | * including optional fields) while the valued fields are actual event fields. | |
306dc902 | 37 | * |
b9e37ffd FC |
38 | * @version 1.0 |
39 | * @author Francois Chouinard | |
306dc902 | 40 | * |
b9e37ffd | 41 | * @see ITmfEvent |
f7703ed6 | 42 | * @see ITmfEventType |
8c8bf09f | 43 | */ |
80349bf7 | 44 | public class TmfEventField implements ITmfEventField { |
8c8bf09f | 45 | |
cbd4ad82 | 46 | // ------------------------------------------------------------------------ |
8c8bf09f | 47 | // Attributes |
cbd4ad82 | 48 | // ------------------------------------------------------------------------ |
8c8bf09f | 49 | |
b742c196 AM |
50 | private final @NonNull String fName; |
51 | private final @Nullable Object fValue; | |
5db5a3a4 | 52 | private final @NonNull Map<String, ITmfEventField> fFields; |
085d898f | 53 | |
cbd4ad82 | 54 | // ------------------------------------------------------------------------ |
8c8bf09f | 55 | // Constructors |
cbd4ad82 FC |
56 | // ------------------------------------------------------------------------ |
57 | ||
8c8bf09f | 58 | /** |
cbbcc354 | 59 | * Full constructor |
306dc902 | 60 | * |
b742c196 AM |
61 | * @param name |
62 | * the event field id | |
63 | * @param value | |
64 | * the event field value | |
65 | * @param fields | |
66 | * the list of subfields | |
67 | * @throws IllegalArgumentException | |
68 | * If 'name' is null, or if 'fields' has duplicate field names. | |
8c8bf09f | 69 | */ |
4c4e2816 | 70 | public TmfEventField(@NonNull String name, @Nullable Object value, ITmfEventField @Nullable [] fields) { |
4c564a2d | 71 | fName = name; |
cbbcc354 | 72 | fValue = value; |
80349bf7 | 73 | |
b742c196 | 74 | if (fields == null) { |
0e4f957e | 75 | fFields = ImmutableMap.of(); |
b742c196 | 76 | } else { |
b742c196 | 77 | ImmutableMap.Builder<String, ITmfEventField> mapBuilder = new ImmutableMap.Builder<>(); |
4c4e2816 | 78 | Arrays.stream(fields).forEach(t -> mapBuilder.put(t.getName(), t)); |
0e4f957e | 79 | fFields = mapBuilder.build(); |
80349bf7 | 80 | } |
28b94d61 FC |
81 | } |
82 | ||
83 | /** | |
cbbcc354 | 84 | * Copy constructor |
306dc902 | 85 | * |
cbbcc354 | 86 | * @param field the other event field |
28b94d61 | 87 | */ |
085d898f | 88 | public TmfEventField(final TmfEventField field) { |
b9e37ffd | 89 | if (field == null) { |
085d898f | 90 | throw new IllegalArgumentException(); |
b9e37ffd | 91 | } |
085d898f FC |
92 | fName = field.fName; |
93 | fValue = field.fValue; | |
94 | fFields = field.fFields; | |
28b94d61 FC |
95 | } |
96 | ||
cbd4ad82 | 97 | // ------------------------------------------------------------------------ |
cbbcc354 | 98 | // ITmfEventField |
cbd4ad82 | 99 | // ------------------------------------------------------------------------ |
8c8bf09f | 100 | |
d7dbf09a | 101 | @Override |
4c564a2d FC |
102 | public String getName() { |
103 | return fName; | |
28b94d61 FC |
104 | } |
105 | ||
d7dbf09a | 106 | @Override |
8c8bf09f ASL |
107 | public Object getValue() { |
108 | return fValue; | |
109 | } | |
110 | ||
d7dbf09a | 111 | @Override |
ac2ae0d8 | 112 | public final Collection<String> getFieldNames() { |
0e4f957e | 113 | return fFields.keySet(); |
4c564a2d FC |
114 | } |
115 | ||
d7dbf09a | 116 | @Override |
ac2ae0d8 | 117 | public final Collection<ITmfEventField> getFields() { |
0e4f957e | 118 | return fFields.values(); |
4c564a2d FC |
119 | } |
120 | ||
d7dbf09a | 121 | @Override |
97de0bca PT |
122 | public ITmfEventField getField(final String... path) { |
123 | if (path.length == 1) { | |
124 | return fFields.get(path[0]); | |
125 | } | |
6c204912 | 126 | ITmfEventField field = this; |
97de0bca | 127 | for (String name : path) { |
6c204912 GB |
128 | field = field.getField(name); |
129 | if (field == null) { | |
130 | return null; | |
131 | } | |
132 | } | |
133 | return field; | |
134 | } | |
135 | ||
4c564a2d FC |
136 | // ------------------------------------------------------------------------ |
137 | // Operations | |
138 | // ------------------------------------------------------------------------ | |
139 | ||
140 | /** | |
141 | * Create a root field from a list of labels. | |
306dc902 | 142 | * |
4c564a2d FC |
143 | * @param labels the list of labels |
144 | * @return the (flat) root list | |
145 | */ | |
66838307 | 146 | public static final @NonNull ITmfEventField makeRoot(final String[] labels) { |
085d898f | 147 | final ITmfEventField[] fields = new ITmfEventField[labels.length]; |
b9e37ffd | 148 | for (int i = 0; i < labels.length; i++) { |
fafdd006 AM |
149 | String label = checkNotNull(labels[i]); |
150 | fields[i] = new TmfEventField(label, null, null); | |
b9e37ffd FC |
151 | } |
152 | // Return a new root field; | |
214cc822 | 153 | return new TmfEventField(ITmfEventField.ROOT_FIELD_ID, null, fields); |
4c564a2d FC |
154 | } |
155 | ||
cbd4ad82 FC |
156 | // ------------------------------------------------------------------------ |
157 | // Object | |
158 | // ------------------------------------------------------------------------ | |
8c8bf09f | 159 | |
28b94d61 | 160 | @Override |
cbd4ad82 | 161 | public int hashCode() { |
cbbcc354 | 162 | final int prime = 31; |
163 | int result = 1; | |
ac2ae0d8 AM |
164 | result = prime * result + getName().hashCode(); |
165 | result = prime * result + ObjectUtils.deepHashCode(getValue()); | |
40d8c779 | 166 | result = prime * result + fFields.hashCode(); |
2fb2eb37 | 167 | return result; |
cbd4ad82 FC |
168 | } |
169 | ||
cbbcc354 | 170 | @Override |
085d898f | 171 | public boolean equals(final Object obj) { |
b9e37ffd | 172 | if (this == obj) { |
cbbcc354 | 173 | return true; |
b9e37ffd FC |
174 | } |
175 | if (obj == null) { | |
cbbcc354 | 176 | return false; |
b9e37ffd | 177 | } |
ac2ae0d8 AM |
178 | |
179 | /* We only consider equals fields of the exact same class. */ | |
180 | if (!(this.getClass().equals(obj.getClass()))) { | |
cbbcc354 | 181 | return false; |
b9e37ffd | 182 | } |
40d8c779 | 183 | |
085d898f | 184 | final TmfEventField other = (TmfEventField) obj; |
40d8c779 | 185 | |
ac2ae0d8 AM |
186 | /* Check that the field names are the same. */ |
187 | if (!NonNullUtils.equalsNullable(getName(), other.getName())) { | |
cbbcc354 | 188 | return false; |
b9e37ffd | 189 | } |
40d8c779 | 190 | |
ac2ae0d8 AM |
191 | /* |
192 | * Check that the field values are the same. We use ObjectUtils to | |
193 | * handle cases where the Object values may be primitive and/or nested | |
194 | * arrays. | |
195 | */ | |
196 | if (!ObjectUtils.deepEquals(this.getValue(), other.getValue())) { | |
cbbcc354 | 197 | return false; |
b9e37ffd | 198 | } |
40d8c779 | 199 | |
ac2ae0d8 | 200 | /* Check that sub-fields are the same. */ |
40d8c779 AM |
201 | if (!fFields.equals(other.fFields)) { |
202 | return false; | |
203 | } | |
204 | ||
cbbcc354 | 205 | return true; |
28b94d61 FC |
206 | } |
207 | ||
82b08e62 | 208 | @Override |
cbbcc354 | 209 | public String toString() { |
306dc902 AM |
210 | StringBuilder ret = new StringBuilder(); |
211 | if (fName.equals(ITmfEventField.ROOT_FIELD_ID)) { | |
212 | /* | |
213 | * If this field is a top-level "field container", we will print its | |
214 | * sub-fields directly. | |
215 | */ | |
216 | appendSubFields(ret); | |
217 | ||
218 | } else { | |
219 | /* The field has its own values */ | |
220 | ret.append(fName); | |
221 | ret.append('='); | |
222 | ret.append(fValue); | |
223 | ||
b742c196 | 224 | if (!fFields.isEmpty()) { |
306dc902 AM |
225 | /* |
226 | * In addition to its own name/value, this field also has | |
227 | * sub-fields. | |
228 | */ | |
229 | ret.append(" ["); //$NON-NLS-1$ | |
230 | appendSubFields(ret); | |
231 | ret.append(']'); | |
232 | } | |
233 | } | |
234 | return ret.toString(); | |
235 | } | |
236 | ||
237 | private void appendSubFields(StringBuilder sb) { | |
b742c196 AM |
238 | Joiner joiner = Joiner.on(", ").skipNulls(); //$NON-NLS-1$ |
239 | sb.append(joiner.join(getFields())); | |
8c8bf09f | 240 | } |
1f506a43 | 241 | |
8f86c552 GB |
242 | @Override |
243 | public String getFormattedValue() { | |
244 | return getValue().toString(); | |
245 | } | |
246 | ||
cbbcc354 | 247 | } |