1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package com.rapiddweller.model.data;
28
29 import com.rapiddweller.common.Named;
30 import com.rapiddweller.common.NullSafeComparator;
31 import com.rapiddweller.common.Operation;
32 import com.rapiddweller.common.StringUtil;
33 import com.rapiddweller.common.collection.OrderedNameMap;
34 import com.rapiddweller.common.converter.AnyConverter;
35 import com.rapiddweller.common.converter.ToStringConverter;
36
37 import java.util.List;
38
39
40
41
42
43
44
45
46 public class FeatureDescriptor implements Named {
47
48
49
50
51 public static final String NAME = "name";
52
53
54
55 protected OrderedNameMap<FeatureDetail<?>> details;
56
57
58
59 protected DescriptorProvider provider;
60
61
62
63
64 private String name;
65
66
67
68
69
70
71
72
73
74 public FeatureDescriptor(String name, DescriptorProvider provider) {
75 if (provider == null) {
76 throw new IllegalArgumentException("provider is null");
77 }
78 if (provider.getDataModel() == null) {
79 throw new IllegalArgumentException("provider's data model is null");
80 }
81 this.details = new OrderedNameMap<>();
82 this.provider = provider;
83 this.addConstraint(NAME, String.class, null);
84 this.setName(name);
85 }
86
87
88
89 @Override
90 public String getName() {
91 return name;
92 }
93
94
95
96
97
98
99 public void setName(String name) {
100 this.name = name;
101 setDetailValue(NAME, name);
102 }
103
104
105
106
107
108
109 public DescriptorProvider getProvider() {
110 return provider;
111 }
112
113
114
115
116
117
118 public DataModel getDataModel() {
119 return provider.getDataModel();
120 }
121
122
123
124
125
126
127
128
129
130 public boolean supportsDetail(String name) {
131 return details.containsKey(name);
132 }
133
134
135
136
137
138
139
140 public Object getDeclaredDetailValue(
141 String name) {
142 return getConfiguredDetail(name).getValue();
143 }
144
145
146
147
148
149
150
151 public Object getDetailValue(
152 String name) {
153 return this.getConfiguredDetail(name).getValue();
154 }
155
156
157
158
159
160
161
162 public void setDetailValue(String detailName, Object detailValue) {
163 if ("name"
164 .equals(detailName)) {
165
166 this.name = (String) detailValue;
167 }
168 FeatureDetail<Object> detail = getConfiguredDetail(detailName);
169 Class<Object> detailType = detail.getType();
170 if (detailValue != null &&
171 !detailType.isAssignableFrom(detailValue.getClass())) {
172 detailValue = AnyConverter.convert(detailValue, detailType);
173 }
174 detail.setValue(detailValue);
175 }
176
177
178
179
180
181
182 public List<FeatureDetail<?>> getDetails() {
183 return details.values();
184 }
185
186
187
188 @Override
189 public String toString() {
190 String name = getName();
191 if (StringUtil.isEmpty(name)) {
192 name = "anonymous";
193 }
194 return renderDetails(new StringBuilder(name)).toString();
195 }
196
197 @Override
198 public boolean equals(Object o) {
199 if (this == o) {
200 return true;
201 }
202 if (o == null || getClass() != o.getClass()) {
203 return false;
204 }
205 final FeatureDescriptor../com/rapiddweller/model/data/FeatureDescriptor.html#FeatureDescriptor">FeatureDescriptor that = (FeatureDescriptor) o;
206 for (FeatureDetail<?> detail : details.values()) {
207 String detailName = detail.getName();
208 if (!NullSafeComparator
209 .equals(detail.getValue(),
210 that.getDetailValue(detailName))) {
211 return false;
212 }
213 }
214 return true;
215 }
216
217 @Override
218 public int hashCode() {
219 return getClass().hashCode() * 29 + details.hashCode();
220 }
221
222
223
224
225
226
227
228
229 protected String renderDetails() {
230 return renderDetails(new StringBuilder()).toString();
231 }
232
233
234
235
236
237
238
239 protected StringBuilder renderDetails(StringBuilder builder) {
240 builder.append("[");
241 boolean empty = true;
242 for (FeatureDetail<?> descriptor : details.values()) {
243 if (descriptor.getValue() != null &&
244 !NAME.equals(descriptor.getName())) {
245 if (!empty) {
246 builder.append(", ");
247 }
248 empty = false;
249 builder.append(descriptor.getName()).append("=");
250 builder.append(ToStringConverter
251 .convert(descriptor.getValue(), "[null]"));
252 }
253 }
254 return builder.append("]");
255 }
256
257
258
259
260
261
262
263 protected Class<?> getDetailType(String detailName) {
264 FeatureDetail<?> detail = details.get(detailName);
265 if (detail == null) {
266 throw new UnsupportedOperationException(
267 "Feature detail not supported: " + detailName);
268 }
269 return detail.getType();
270 }
271
272
273
274
275
276
277
278
279 protected <T> void addConfig(String name, Class<T> type) {
280 addConfig(name, type, false);
281 }
282
283
284
285
286
287
288
289
290
291 protected <T> void addConfig(String name, Class<T> type,
292 boolean deprecated) {
293 addDetail(name, type, false, deprecated, null);
294 }
295
296
297
298
299
300
301
302
303
304 protected <T> void addConstraint(String name, Class<T> type,
305 Operation<T, T> combinator) {
306 addDetail(name, type, true, false, combinator);
307 }
308
309
310
311
312
313
314
315
316
317
318
319 protected <T> void addDetail(String detailName, Class<T> detailType,
320 boolean constraint,
321 boolean deprecated,
322 Operation<T, T> combinator) {
323 this.details.put(detailName,
324 new FeatureDetail<>(detailName, detailType, constraint,
325 combinator));
326 }
327
328
329
330
331
332
333
334
335
336
337 @SuppressWarnings("unchecked")
338 public <T> FeatureDetail<T> getConfiguredDetail(String name) {
339 if (!supportsDetail(name)) {
340 throw new UnsupportedOperationException("Feature detail '" + name +
341 "' not supported in feature type: " + getClass().getName());
342 }
343 return (FeatureDetail<T>) details.get(name);
344 }
345
346 }