Commit | Line | Data |
---|---|---|
9447c7ee | 1 | /******************************************************************************* |
40dfafb3 | 2 | * Copyright (c) 2015 Ericsson |
9447c7ee AM |
3 | * |
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 | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
40dfafb3 | 10 | * Patrick Tasse - Initial API and implementation |
9447c7ee AM |
11 | *******************************************************************************/ |
12 | ||
13 | package org.eclipse.tracecompass.tmf.core.event.aspect; | |
14 | ||
11124ee6 PT |
15 | import java.util.ArrayList; |
16 | import java.util.List; | |
17 | ||
9447c7ee AM |
18 | import org.eclipse.jdt.annotation.Nullable; |
19 | import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; | |
20 | import org.eclipse.tracecompass.tmf.core.event.ITmfEventField; | |
21 | ||
22 | /** | |
40dfafb3 | 23 | * Event aspect that resolves to a root event field, or one of its subfields. |
9447c7ee | 24 | * |
40dfafb3 PT |
25 | * When used, the subfield pattern is slash-prefixed and slash-separated, and |
26 | * the backslash character is used to escape an uninterpreted slash. | |
27 | * | |
28 | * @author Patrick Tasse | |
9447c7ee | 29 | */ |
ec48d248 | 30 | public class TmfEventFieldAspect implements ITmfEventAspect<Object> { |
9447c7ee | 31 | |
11124ee6 PT |
32 | private static final char SLASH = '/'; |
33 | private static final char BACKSLASH = '\\'; | |
34 | ||
9447c7ee | 35 | private final String fAspectName; |
40dfafb3 PT |
36 | private final IRootField fRootField; |
37 | private final @Nullable String fFieldPath; | |
97de0bca | 38 | private final String[] fFieldArray; |
9447c7ee | 39 | |
40dfafb3 PT |
40 | /** |
41 | * Interface for the root field resolver | |
42 | */ | |
43 | public interface IRootField { | |
44 | /** | |
45 | * Returns the root event field for this aspect. Implementations must | |
46 | * override to provide a specific event member but should not assume the | |
47 | * event is of any specific type. | |
48 | * | |
49 | * @param event | |
50 | * The event to process | |
51 | * @return the root event field | |
52 | */ | |
53 | public @Nullable ITmfEventField getRootField(ITmfEvent event); | |
54 | } | |
55 | ||
9447c7ee AM |
56 | /** |
57 | * Constructor | |
58 | * | |
59 | * @param aspectName | |
60 | * The name of the aspect. Should be localized. | |
40dfafb3 PT |
61 | * @param fieldPath |
62 | * The field name or subfield pattern to resolve the event, or | |
63 | * null to use the root field. Should *not* be localized! | |
64 | * @param rootField | |
65 | * The root field resolver object | |
9447c7ee | 66 | */ |
40dfafb3 | 67 | public TmfEventFieldAspect(String aspectName, @Nullable String fieldPath, IRootField rootField) { |
9447c7ee | 68 | fAspectName = aspectName; |
40dfafb3 PT |
69 | fFieldPath = fieldPath; |
70 | fFieldArray = getFieldArray(fieldPath); | |
71 | fRootField = rootField; | |
72 | } | |
73 | ||
74 | /** | |
75 | * Get the field name or subfield pattern to resolve the event, or null if | |
76 | * the root field is used. | |
77 | * | |
78 | * @return the field name, subfield pattern, or null | |
79 | */ | |
80 | public @Nullable String getFieldPath() { | |
81 | return fFieldPath; | |
82 | } | |
11124ee6 | 83 | |
40dfafb3 PT |
84 | /** |
85 | * Create a new instance of the aspect for the specified field name or | |
86 | * subfield pattern, relative to the root field, or null for the root | |
87 | * field. | |
88 | * | |
89 | * @param fieldPath | |
90 | * The field name or subfield pattern to resolve the event, or | |
91 | * null. | |
92 | * @return a new aspect instance | |
93 | */ | |
94 | public TmfEventFieldAspect forField(@Nullable String fieldPath) { | |
95 | return new TmfEventFieldAspect(fAspectName, fieldPath, fRootField); | |
9447c7ee AM |
96 | } |
97 | ||
98 | @Override | |
99 | public String getName() { | |
100 | return fAspectName; | |
101 | } | |
102 | ||
103 | @Override | |
104 | public String getHelpText() { | |
105 | return EMPTY_STRING; | |
106 | } | |
107 | ||
108 | @Override | |
40dfafb3 PT |
109 | public @Nullable Object resolve(ITmfEvent event) { |
110 | ITmfEventField root = fRootField.getRootField(event); | |
111 | if (root == null) { | |
112 | return null; | |
113 | } | |
114 | if (fFieldArray.length == 0) { | |
115 | return root; | |
116 | } | |
117 | ITmfEventField field = root.getField(fFieldArray); | |
9447c7ee | 118 | if (field == null) { |
2a28075c | 119 | return null; |
9447c7ee | 120 | } |
40dfafb3 | 121 | return field.getValue(); |
9447c7ee AM |
122 | } |
123 | ||
9447c7ee AM |
124 | // ------------------------------------------------------------------------ |
125 | // hashCode/equals | |
126 | // Typically we want identical field aspects to be merged together. | |
127 | // ------------------------------------------------------------------------ | |
128 | ||
129 | @Override | |
130 | public int hashCode() { | |
131 | final int prime = 31; | |
132 | int result = 1; | |
133 | result = prime * result + fAspectName.hashCode(); | |
40dfafb3 PT |
134 | String fieldPath = fFieldPath; |
135 | result = prime * result + (fieldPath == null ? 0 : fieldPath.hashCode()); | |
9447c7ee AM |
136 | return result; |
137 | } | |
138 | ||
139 | @Override | |
140 | public boolean equals(@Nullable Object obj) { | |
141 | if (this == obj) { | |
142 | return true; | |
143 | } | |
11124ee6 PT |
144 | if (obj == null) { |
145 | return false; | |
146 | } | |
147 | if (!this.getClass().equals(obj.getClass())) { | |
9447c7ee AM |
148 | return false; |
149 | } | |
150 | TmfEventFieldAspect other = (TmfEventFieldAspect) obj; | |
151 | if (!fAspectName.equals(other.fAspectName)) { | |
152 | return false; | |
153 | } | |
40dfafb3 PT |
154 | String fieldPath = fFieldPath; |
155 | if (fieldPath == null) { | |
156 | if (other.fFieldPath != null) { | |
157 | return false; | |
158 | } | |
159 | } else if (!fieldPath.equals(other.fFieldPath)) { | |
9447c7ee AM |
160 | return false; |
161 | } | |
162 | return true; | |
163 | } | |
11124ee6 | 164 | |
40dfafb3 PT |
165 | private static String[] getFieldArray(@Nullable String field) { |
166 | ||
167 | if (field == null) { | |
168 | return new String[0]; | |
169 | } | |
170 | ||
171 | if (field.charAt(0) != SLASH) { | |
172 | return new String[] { field }; | |
173 | } | |
11124ee6 PT |
174 | |
175 | StringBuilder sb = new StringBuilder(); | |
176 | List<String> list = new ArrayList<>(); | |
177 | ||
178 | // We start at 1 since the first character is a slash that we want to | |
179 | // ignore. | |
180 | for (int i = 1; i < field.length(); i++) { | |
181 | char charAt = field.charAt(i); | |
182 | if (charAt == SLASH) { | |
183 | // char is slash. Cut here. | |
184 | list.add(sb.toString()); | |
185 | sb = new StringBuilder(); | |
186 | } else if ((charAt == BACKSLASH) && (i < field.length() - 1) && (field.charAt(i + 1) == SLASH)) { | |
187 | // Uninterpreted slash. Add it. | |
188 | sb.append(SLASH); | |
189 | i++; | |
190 | } else { | |
191 | // Any other character. Add. | |
192 | sb.append(charAt); | |
193 | } | |
194 | } | |
195 | ||
196 | // Last block. Add it to list. | |
197 | list.add(sb.toString()); | |
198 | ||
199 | // Transform to array | |
200 | String[] array = new String[list.size()]; | |
201 | list.toArray(array); | |
202 | ||
203 | return array; | |
204 | } | |
9447c7ee | 205 | } |