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