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