Skip to contentPackage: DatastoreUtils$IndexType
DatastoreUtils$IndexType
Coverage
1: /*******************************************************************************
2: * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others
3: *
4: * This program and the accompanying materials are made
5: * available under the terms of the Eclipse Public License 2.0
6: * which is available at https://www.eclipse.org/legal/epl-2.0/
7: *
8: * SPDX-License-Identifier: EPL-2.0
9: *
10: * Contributors:
11: * Eurotech - initial API and implementation
12: * Red Hat Inc
13: *******************************************************************************/
14: package org.eclipse.kapua.service.datastore.internal.mediator;
15:
16: import com.google.common.hash.Hashing;
17: import org.apache.commons.lang3.StringUtils;
18: import org.eclipse.kapua.KapuaErrorCodes;
19: import org.eclipse.kapua.KapuaException;
20: import org.eclipse.kapua.commons.util.KapuaDateUtils;
21: import org.eclipse.kapua.model.id.KapuaId;
22: import org.eclipse.kapua.service.datastore.internal.setting.DatastoreSettings;
23: import org.eclipse.kapua.service.datastore.internal.setting.DatastoreSettingsKey;
24: import org.slf4j.Logger;
25: import org.slf4j.LoggerFactory;
26:
27: import javax.validation.constraints.NotNull;
28: import java.nio.charset.StandardCharsets;
29: import java.text.ParseException;
30: import java.time.Instant;
31: import java.time.LocalDateTime;
32: import java.time.ZoneOffset;
33: import java.time.format.DateTimeFormatter;
34: import java.time.format.DateTimeFormatterBuilder;
35: import java.time.format.DateTimeParseException;
36: import java.time.format.ResolverStyle;
37: import java.time.temporal.ChronoField;
38: import java.time.temporal.ChronoUnit;
39: import java.time.temporal.TemporalAccessor;
40: import java.time.temporal.WeekFields;
41: import java.util.ArrayList;
42: import java.util.Base64;
43: import java.util.Date;
44: import java.util.List;
45: import java.util.regex.Pattern;
46:
47: /**
48: * Datastore utility class
49: *
50: * @since 1.0.0
51: */
52: public class DatastoreUtils {
53:
54: private static final Logger LOG = LoggerFactory.getLogger(DatastoreUtils.class);
55:
56: private enum IndexType { CHANNEL, CLIENT, METRIC }
57:
58: private DatastoreUtils() {
59: }
60:
61: private static final char SPECIAL_DOT = '.';
62: private static final String SPECIAL_DOT_ESC = "$2e";
63:
64: private static final char SPECIAL_DOLLAR = '$';
65: private static final String SPECIAL_DOLLAR_ESC = "$24";
66:
67: private static final String UNKNOWN_TYPE = "Unknown type [%s]";
68: private static final String TYPE_CANNOT_BE_CONVERTED = "Type [%s] cannot be converted to Double!";
69:
70: public static final CharSequence ILLEGAL_CHARS = "\"\\/*?<>|,. ";
71:
72: public static final String CLIENT_METRIC_TYPE_STRING = "string";
73: public static final String CLIENT_METRIC_TYPE_INTEGER = "integer";
74: public static final String CLIENT_METRIC_TYPE_LONG = "long";
75: public static final String CLIENT_METRIC_TYPE_FLOAT = "float";
76: public static final String CLIENT_METRIC_TYPE_DOUBLE = "double";
77: public static final String CLIENT_METRIC_TYPE_DATE = "date";
78: public static final String CLIENT_METRIC_TYPE_BOOLEAN = "boolean";
79: public static final String CLIENT_METRIC_TYPE_BINARY = "binary";
80:
81: public static final String CLIENT_METRIC_TYPE_STRING_ACRONYM = "str";
82: public static final String CLIENT_METRIC_TYPE_INTEGER_ACRONYM = "int";
83: public static final String CLIENT_METRIC_TYPE_LONG_ACRONYM = "lng";
84: public static final String CLIENT_METRIC_TYPE_FLOAT_ACRONYM = "flt";
85: public static final String CLIENT_METRIC_TYPE_DOUBLE_ACRONYM = "dbl";
86: public static final String CLIENT_METRIC_TYPE_DATE_ACRONYM = "dte";
87: public static final String CLIENT_METRIC_TYPE_BOOLEAN_ACRONYM = "bln";
88: public static final String CLIENT_METRIC_TYPE_BINARY_ACRONYM = "bin";
89:
90: public static final String INDEXING_WINDOW_OPTION_WEEK = "week";
91: public static final String INDEXING_WINDOW_OPTION_DAY = "day";
92: public static final String INDEXING_WINDOW_OPTION_HOUR = "hour";
93:
94: public static final String DATASTORE_DATE_FORMAT = "8" + KapuaDateUtils.ISO_DATE_PATTERN; // example 2017-01-24T11:22:10.999Z
95:
96: private static final DateTimeFormatter DATA_INDEX_FORMATTER_WEEK = new DateTimeFormatterBuilder()
97: .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
98: .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
99: .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
100: .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
101: .appendPattern("YYYY-ww")
102: .toFormatter(KapuaDateUtils.getLocale())
103: .withLocale(KapuaDateUtils.getLocale())
104: .withResolverStyle(ResolverStyle.STRICT)
105: .withZone(KapuaDateUtils.getTimeZone());
106: private static final DateTimeFormatter DATA_INDEX_FORMATTER_DAY = new DateTimeFormatterBuilder()
107: .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
108: .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
109: .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
110: .appendPattern("YYYY-ww-ee")
111: .toFormatter(KapuaDateUtils.getLocale())
112: .withLocale(KapuaDateUtils.getLocale())
113: .withResolverStyle(ResolverStyle.STRICT)
114: .withZone(KapuaDateUtils.getTimeZone());
115: private static final DateTimeFormatter DATA_INDEX_FORMATTER_HOUR = new DateTimeFormatterBuilder()
116: .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
117: .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
118: .appendPattern("YYYY-ww-ee-HH")
119: .toFormatter(KapuaDateUtils.getLocale())
120: .withLocale(KapuaDateUtils.getLocale())
121: .withResolverStyle(ResolverStyle.STRICT)
122: .withZone(KapuaDateUtils.getTimeZone());
123:
124: /**
125: * Return the hash code for the provided components (typically components are a sequence of account - client id - channel ...)
126: *
127: * @param components
128: * @return
129: */
130: public static String getHashCode(String... components) {
131: String concatString = "";
132: for (String str : components) {
133: concatString = concatString.concat(str);
134: }
135:
136: byte[] hashCode = Hashing.sha256()
137: .hashString(concatString, StandardCharsets.UTF_8)
138: .asBytes();
139:
140: // ES 5.2 FIX
141: // return Base64.encodeBytes(hashCode);
142: return Base64.getUrlEncoder().withoutPadding().encodeToString(hashCode);
143: }
144:
145: private static String normalizeIndexName(String name) {
146: String normName = null;
147: try {
148: DatastoreUtils.checkIdxAliasName(name);
149: normName = name;
150: } catch (IllegalArgumentException exc) {
151: LOG.trace(exc.getMessage(), exc);
152: normName = name.toLowerCase().replace(ILLEGAL_CHARS, "_");
153: DatastoreUtils.checkIdxAliasName(normName);
154: }
155: return normName;
156: }
157:
158: /**
159: * Normalize the metric name to be compliant to Kapua/Elasticserach constraints.<br>
160: * It escapes the '$' and '.'
161: *
162: * @param name
163: * @return The normalized metric name
164: * @since 1.0.0
165: */
166: public static String normalizeMetricName(String name) {
167: String newName = name;
168: if (newName.contains(".")) {
169: newName = newName.replace(String.valueOf(SPECIAL_DOLLAR), SPECIAL_DOLLAR_ESC);
170: newName = newName.replace(String.valueOf(SPECIAL_DOT), SPECIAL_DOT_ESC);
171: LOG.trace(String.format("Metric %s contains a special char '%s' that will be replaced with '%s'", name, String.valueOf(SPECIAL_DOT), SPECIAL_DOT_ESC));
172: }
173: return newName;
174: }
175:
176: /**
177: * Restore the metric name, so switch back to the 'not escaped' values for '$' and '.'
178: *
179: * @param normalizedName
180: * @return The restored metric name
181: * @since 1.0.0
182: */
183: public static String restoreMetricName(String normalizedName) {
184: String oldName = normalizedName;
185: oldName = oldName.replace(SPECIAL_DOT_ESC, String.valueOf(SPECIAL_DOT));
186: oldName = oldName.replace(SPECIAL_DOLLAR_ESC, String.valueOf(SPECIAL_DOLLAR));
187: return oldName;
188: }
189:
190: /**
191: * Return the metric parts for the composed metric name (split the metric name by '.')
192: *
193: * @param fullName
194: * @return
195: */
196: public static String[] getMetricParts(String fullName) {
197: return fullName == null ? null : fullName.split(Pattern.quote("."));
198: }
199:
200: /**
201: * Check the index alias correctness.<br>
202: * The alias cnnot be null, starts with '_', contains uppercase character or contains {@link DatastoreUtils#ILLEGAL_CHARS}
203: *
204: * @param alias
205: * @since 1.0.0
206: */
207: public static void checkIdxAliasName(String alias) {
208: if (alias == null || alias.isEmpty()) {
209: throw new IllegalArgumentException(String.format("Alias name cannot be %s", alias == null ? "null" : "empty"));
210: }
211: if (alias.startsWith("_")) {
212: throw new IllegalArgumentException(String.format("Alias name cannot start with _"));
213: }
214: for (int i = 0; i < alias.length(); i++) {
215: if (Character.isUpperCase(alias.charAt(i))) {
216: throw new IllegalArgumentException(String.format("Alias name cannot contain uppercase chars [found %s]", alias.charAt(i)));
217: }
218: }
219: if (alias.contains(ILLEGAL_CHARS)) {
220: throw new IllegalArgumentException(String.format("Alias name cannot contain special chars [found oneof %s]", ILLEGAL_CHARS));
221: }
222: }
223:
224: /**
225: * Check the index name ({@link DatastoreUtils#checkIdxAliasName(String index)}
226: *
227: * @param index
228: * @since 1.0.0
229: */
230: public static void checkIdxName(String index) {
231: DatastoreUtils.checkIdxAliasName(index);
232: }
233:
234: /**
235: * Normalize the index alias name and replace the '-' with '_'
236: *
237: * @param alias
238: * @return The normalized index alias
239: * @since 1.0.0
240: */
241: public static String normalizeIndexAliasName(String alias) {
242: String aliasName = normalizeIndexName(alias);
243: aliasName = aliasName.replace("-", "_");
244: return aliasName;
245: }
246:
247: /**
248: * Normalize the account index name and and the suffix '-*'
249: *
250: * @param scopeId
251: * @return
252: */
253: public static String getDataIndexName(KapuaId scopeId) {
254: final StringBuilder sb = new StringBuilder();
255: final String prefix = DatastoreSettings.getInstance().getString(DatastoreSettingsKey.INDEX_PREFIX);
256: if (StringUtils.isNotEmpty(prefix)) {
257: sb.append(prefix).append("-");
258: }
259: String indexName = DatastoreUtils.normalizedIndexName(scopeId.toStringId());
260: sb.append(indexName).append("-").append("data-message").append("-*");
261: return sb.toString();
262: }
263:
264: /**
265: * Get the data index for the specified base name and timestamp
266: *
267: * @param scopeId
268: * @param timestamp
269: * @return
270: */
271: public static String getDataIndexName(KapuaId scopeId, long timestamp, String indexingWindowOption) throws KapuaException {
272: final StringBuilder sb = new StringBuilder();
273: final String prefix = DatastoreSettings.getInstance().getString(DatastoreSettingsKey.INDEX_PREFIX);
274: if (StringUtils.isNotEmpty(prefix)) {
275: sb.append(prefix).append("-");
276: }
277: final String actualName = DatastoreUtils.normalizedIndexName(scopeId.toStringId());
278: sb.append(actualName).append('-').append("data-message").append('-');
279: DateTimeFormatter formatter;
280: switch (indexingWindowOption) {
281: default:
282: case INDEXING_WINDOW_OPTION_WEEK:
283: formatter = DATA_INDEX_FORMATTER_WEEK;
284: break;
285: case INDEXING_WINDOW_OPTION_DAY:
286: formatter = DATA_INDEX_FORMATTER_DAY;
287: break;
288: case INDEXING_WINDOW_OPTION_HOUR:
289: formatter = DATA_INDEX_FORMATTER_HOUR;
290: break;
291: }
292: formatter.formatTo(Instant.ofEpochMilli(timestamp).atOffset(ZoneOffset.UTC), sb);
293: return sb.toString();
294: }
295:
296: public static String getChannelIndexName(KapuaId scopeId) {
297: return getRegistryIndexName(scopeId, IndexType.CHANNEL);
298: }
299:
300: public static String getClientIndexName(KapuaId scopeId) {
301: return getRegistryIndexName(scopeId, IndexType.CLIENT);
302: }
303:
304: public static String getMetricIndexName(KapuaId scopeId) {
305: return getRegistryIndexName(scopeId, IndexType.METRIC);
306: }
307:
308: /**
309: * Get the Kapua index name for the specified base name
310: *
311: * @param scopeId
312: * @return The Kapua index name
313: * @since 1.0.0
314: */
315: private static String getRegistryIndexName(KapuaId scopeId, IndexType indexType) {
316: final StringBuilder sb = new StringBuilder();
317: final String prefix = DatastoreSettings.getInstance().getString(DatastoreSettingsKey.INDEX_PREFIX);
318: if (StringUtils.isNotEmpty(prefix)) {
319: sb.append(prefix).append("-");
320: }
321: String indexName = DatastoreUtils.normalizedIndexName(scopeId.toStringId());
322: sb.append(indexName);
323: sb.append("-data-").append(indexType.name().toLowerCase());
324: return sb.toString();
325: }
326:
327: /**
328: * Normalize the index ({@link DatastoreUtils#normalizeIndexName(String index)}
329: *
330: * @param index
331: * @return
332: */
333: public static String normalizedIndexName(String index) {
334: return normalizeIndexName(index);
335: }
336:
337: /**
338: * Return the list of the data indexes between start and windowEnd instant by scope id.
339: * Only the indexes that will be *FULLY* included in the list (i.e. with a starting date ON OR AFTER the window start AND
340: * the end date ON OR BEFORE the window end will be returned
341: * Only indexes matching Kapua data index name pattern will be inserted inside the result list, namely this format:
342: *
343: * "scopeID-data-message-YYYY-ww"
344: * or
345: * "scopeID-data-message-YYYY-ww-ee"
346: * or
347: * "scopeID-data-message-YYYY-ww-ee-HH"
348: *
349: * @param indexes
350: * @param windowStart
351: * @param windowEnd
352: * @param scopeId
353: * @return The list of the data indexes between start and end
354: * @throws DatastoreException
355: */
356: public static String[] convertToDataIndexes(@NotNull String[] indexes, Instant windowStart, Instant windowEnd, KapuaId scopeId) throws DatastoreException {
357: boolean skipTemporalValidation = false;
358: if (windowStart == null && windowEnd == null) {
359: skipTemporalValidation = true;
360: }
361: List<String> result = new ArrayList<>();
362: for (String index : indexes) {
363: if (index == null) {
364: continue;
365: }
366: if (scopeId != null && (!validatePrefixIndex(index, scopeId))) {
367: continue;
368: }
369: String strippedIndex = stripPrefixAndAccount(index);
370: int fragments = strippedIndex.split("-").length;
371: DateTimeFormatter formatter;
372: ChronoUnit indexUnit;
373: int indexWidth;
374: switch (fragments) {
375: case 2:
376: default:
377: // YYYY-ww
378: formatter = DATA_INDEX_FORMATTER_WEEK;
379: indexUnit = ChronoUnit.DAYS;
380: indexWidth = 7;
381: break;
382: case 3:
383: // YYYY-ww-ee
384: formatter = DATA_INDEX_FORMATTER_DAY;
385: indexUnit = ChronoUnit.DAYS;
386: indexWidth = 1;
387: break;
388: case 4:
389: // YYYY-ww-ee-HH
390: formatter = DATA_INDEX_FORMATTER_HOUR;
391: indexUnit = ChronoUnit.HOURS;
392: indexWidth = 1;
393: break;
394: }
395: TemporalAccessor temporalAccessor;
396: try {
397: temporalAccessor = formatter.parse(strippedIndex);
398: } catch (DateTimeParseException e) {
399: //unable to parse...the format is not right so don't add this index into result-set
400: continue;
401: }
402: if (skipTemporalValidation) { //this index passed format validation...proceed to next index
403: result.add(index);
404: continue;
405: }
406: try {
407: Instant indexStart = LocalDateTime.of(
408: temporalAccessor.get(ChronoField.YEAR),
409: temporalAccessor.get(ChronoField.MONTH_OF_YEAR),
410: temporalAccessor.get(ChronoField.DAY_OF_MONTH),
411: temporalAccessor.get(ChronoField.HOUR_OF_DAY),
412: temporalAccessor.get(ChronoField.MINUTE_OF_HOUR),
413: temporalAccessor.get(ChronoField.SECOND_OF_MINUTE)
414: ).toInstant(ZoneOffset.UTC);
415: Instant indexEnd = indexStart.plus(indexWidth, indexUnit).minusNanos(1);
416:
417: if (windowStart == null && isIndexFullyBeforeInstant(indexStart, indexEnd, windowEnd) ||
418: (windowEnd == null && isIndexFullyAfterInstant(indexStart, indexEnd, windowStart)) ||
419: (windowStart != null && windowEnd != null && isIndexFullyAfterInstant(indexStart, indexEnd, windowStart) && isIndexFullyBeforeInstant(indexStart, indexEnd, windowEnd))) {
420: result.add(index);
421: }
422: } catch (Exception ex) {
423: throw new DatastoreException(KapuaErrorCodes.ILLEGAL_ARGUMENT, ex);
424: }
425: }
426: return result.toArray(new String[0]);
427: }
428:
429: private static boolean validatePrefixIndex(@NotNull String index,@NotNull KapuaId scopeId) {
430: String genericIndexFormat = getDataIndexName(scopeId);
431: return index.startsWith(genericIndexFormat.substring(0, genericIndexFormat.length() - 1));
432: }
433:
434: private static boolean isIndexFullyAfterInstant(@NotNull Instant indexStart, @NotNull Instant indexEnd, @NotNull Instant checkpoint) {
435: return !indexStart.isBefore(checkpoint) && !indexEnd.isBefore(checkpoint);
436: }
437:
438: private static boolean isIndexFullyBeforeInstant(@NotNull Instant indexStart, @NotNull Instant indexEnd, @NotNull Instant checkpoint) {
439: return !indexStart.isAfter(checkpoint) && !indexEnd.isAfter(checkpoint);
440: }
441:
442: private static String stripPrefixAndAccount(@NotNull String index) {
443: return StringUtils.substringAfter(index, "-data-message-");
444: }
445:
446: /**
447: * Get the full metric name used to store the metric in Elasticsearch.<br>
448: * The full metric name is composed by the metric and the type acronym as suffix ('.' is used as separator between the 2 parts)
449: *
450: * @param name
451: * @param type
452: * @return
453: */
454: public static String getMetricValueQualifier(String name, String type) {
455: String shortType = DatastoreUtils.getClientMetricFromAcronym(type);
456: return String.format("%s.%s", name, shortType);
457: }
458:
459: /**
460: * Get the client metric type from the metric value type
461: *
462: * @param clazz
463: * @return The client metric type
464: * @since 1.0.0
465: */
466: public static String getClientMetricFromType(Class<?> clazz) {
467: if (clazz == null) {
468: throw new NullPointerException("Metric value must not be null");
469: }
470: String value;
471: if (clazz == String.class) {
472: value = CLIENT_METRIC_TYPE_STRING;
473: } else if (clazz == Integer.class) {
474: value = CLIENT_METRIC_TYPE_INTEGER;
475: } else if (clazz == Long.class) {
476: value = CLIENT_METRIC_TYPE_LONG;
477: } else if (clazz == Float.class) {
478: value = CLIENT_METRIC_TYPE_FLOAT;
479: } else if (clazz == Double.class) {
480: value = CLIENT_METRIC_TYPE_DOUBLE;
481: } else if (clazz == Boolean.class) {
482: value = CLIENT_METRIC_TYPE_BOOLEAN;
483: } else if (clazz == Date.class) {
484: value = CLIENT_METRIC_TYPE_DATE;
485: } else if (clazz == byte[].class) {
486: value = CLIENT_METRIC_TYPE_BINARY;
487: } else {
488: throw new IllegalArgumentException(String.format("Metric value type for "));
489: }
490: return value;
491: }
492:
493: /**
494: * Get the client metric type acronym for the given client metric type full name
495: *
496: * @param acronym
497: * @return The client metric type acronym
498: * @since 1.0.0
499: */
500: public static String getClientMetricFromAcronym(String acronym) {
501: if (CLIENT_METRIC_TYPE_STRING.equals(acronym)) {
502: return CLIENT_METRIC_TYPE_STRING_ACRONYM;
503: }
504: if (CLIENT_METRIC_TYPE_INTEGER.equals(acronym)) {
505: return CLIENT_METRIC_TYPE_INTEGER_ACRONYM;
506: }
507: if (CLIENT_METRIC_TYPE_LONG.equals(acronym)) {
508: return CLIENT_METRIC_TYPE_LONG_ACRONYM;
509: }
510: if (CLIENT_METRIC_TYPE_FLOAT.equals(acronym)) {
511: return CLIENT_METRIC_TYPE_FLOAT_ACRONYM;
512: }
513: if (CLIENT_METRIC_TYPE_DOUBLE.equals(acronym)) {
514: return CLIENT_METRIC_TYPE_DOUBLE_ACRONYM;
515: }
516: if (CLIENT_METRIC_TYPE_BOOLEAN.equals(acronym)) {
517: return CLIENT_METRIC_TYPE_BOOLEAN_ACRONYM;
518: }
519: if (CLIENT_METRIC_TYPE_DATE.equals(acronym)) {
520: return CLIENT_METRIC_TYPE_DATE_ACRONYM;
521: }
522: if (CLIENT_METRIC_TYPE_BINARY.equals(acronym)) {
523: return CLIENT_METRIC_TYPE_BINARY_ACRONYM;
524: }
525: throw new IllegalArgumentException(String.format(UNKNOWN_TYPE, acronym));
526: }
527:
528: /**
529: * Check if the metric type is date
530: *
531: * @param acronym
532: * @return
533: */
534: public static boolean isDateMetric(String acronym) {
535: return CLIENT_METRIC_TYPE_DATE_ACRONYM.equals(acronym);
536: }
537:
538: /**
539: * Convert the metric value class type (Kapua side) to the proper string type description (client side)
540: *
541: * @param aClass
542: * @return The metric value type converted to string
543: * @since 1.0.0
544: */
545: public static <T> String convertToClientMetricType(Class<T> aClass) {
546: if (aClass == String.class) {
547: return CLIENT_METRIC_TYPE_STRING;
548: }
549: if (aClass == Integer.class) {
550: return CLIENT_METRIC_TYPE_INTEGER;
551: }
552: if (aClass == Long.class) {
553: return CLIENT_METRIC_TYPE_LONG;
554: }
555: if (aClass == Float.class) {
556: return CLIENT_METRIC_TYPE_FLOAT;
557: }
558: if (aClass == Double.class) {
559: return CLIENT_METRIC_TYPE_DOUBLE;
560: }
561: if (aClass == Boolean.class) {
562: return CLIENT_METRIC_TYPE_BOOLEAN;
563: }
564: if (aClass == Date.class) {
565: return CLIENT_METRIC_TYPE_DATE;
566: }
567: if (aClass == byte[].class) {
568: return CLIENT_METRIC_TYPE_BINARY;
569: }
570: throw new IllegalArgumentException(String.format(UNKNOWN_TYPE, aClass.getName()));
571: }
572:
573: /**
574: * Convert the client metric type to the corresponding Kapua type
575: *
576: * @param clientType
577: * @return The concrete metric value type
578: * @since 1.0.0
579: */
580: public static Class<?> convertToKapuaType(String clientType) {
581: Class<?> clazz;
582: if (CLIENT_METRIC_TYPE_STRING.equals(clientType)) {
583: clazz = String.class;
584: } else if (CLIENT_METRIC_TYPE_INTEGER.equals(clientType)) {
585: clazz = Integer.class;
586: } else if (CLIENT_METRIC_TYPE_LONG.equals(clientType)) {
587: clazz = Long.class;
588: } else if (CLIENT_METRIC_TYPE_FLOAT.equals(clientType)) {
589: clazz = Float.class;
590: } else if (CLIENT_METRIC_TYPE_DOUBLE.equals(clientType)) {
591: clazz = Double.class;
592: } else if (CLIENT_METRIC_TYPE_BOOLEAN.equals(clientType)) {
593: clazz = Boolean.class;
594: } else if (CLIENT_METRIC_TYPE_DATE.equals(clientType)) {
595: clazz = Date.class;
596: } else if (CLIENT_METRIC_TYPE_BINARY.equals(clientType)) {
597: clazz = byte[].class;
598: } else {
599: throw new IllegalArgumentException(String.format(UNKNOWN_TYPE, clientType));
600: }
601: return clazz;
602: }
603:
604: /**
605: * Convert the metric value to the correct type using the metric acronym type
606: *
607: * @param acronymType
608: * @param value
609: * @return The concrete metric value type
610: * @since 1.0.0
611: */
612: public static Object convertToCorrectType(String acronymType, Object value) {
613: Object convertedValue = null;
614: if (CLIENT_METRIC_TYPE_DOUBLE_ACRONYM.equals(acronymType)) {
615: if (value instanceof Number) {
616: convertedValue = new Double(((Number) value).doubleValue());
617: } else if (value instanceof String) {
618: convertedValue = Double.parseDouble((String) value);
619: } else {
620: throw new IllegalArgumentException(String.format(TYPE_CANNOT_BE_CONVERTED, getValueClass(value)));
621: }
622: } else if (CLIENT_METRIC_TYPE_FLOAT_ACRONYM.equals(acronymType)) {
623: if (value instanceof Number) {
624: convertedValue = new Float(((Number) value).floatValue());
625: } else if (value instanceof String) {
626: convertedValue = Float.parseFloat((String) value);
627: } else {
628: throw new IllegalArgumentException(String.format(TYPE_CANNOT_BE_CONVERTED, getValueClass(value)));
629: }
630: } else if (CLIENT_METRIC_TYPE_INTEGER_ACRONYM.equals(acronymType)) {
631: if (value instanceof Number) {
632: convertedValue = new Integer(((Number) value).intValue());
633: } else if (value instanceof String) {
634: convertedValue = Integer.parseInt((String) value);
635: } else {
636: throw new IllegalArgumentException(String.format(TYPE_CANNOT_BE_CONVERTED, getValueClass(value)));
637: }
638: } else if (CLIENT_METRIC_TYPE_LONG_ACRONYM.equals(acronymType)) {
639: if (value instanceof Number) {
640: convertedValue = new Long(((Number) value).longValue());
641: } else if (value instanceof String) {
642: convertedValue = Long.parseLong((String) value);
643: } else {
644: throw new IllegalArgumentException(String.format("Type [%s] cannot be converted to Long!", getValueClass(value)));
645: }
646: } else if (CLIENT_METRIC_TYPE_DATE_ACRONYM.equals(acronymType)) {
647: if (value instanceof Date) {
648: convertedValue = (Date) value;
649: } else if (value instanceof String) {
650: try {
651: convertedValue = KapuaDateUtils.parseDate((String) value);
652: } catch (ParseException e) {
653: throw new IllegalArgumentException(
654: String.format("Type [%s] cannot be converted to Date. Allowed format [%s] - Value to convert [%s]!", getValueClass(value), DATASTORE_DATE_FORMAT,
655: value));
656: }
657: } else {
658: throw new IllegalArgumentException(String.format("Type [%s] cannot be converted to Date!", getValueClass(value)));
659: }
660: } else {
661: // no need to translate for others field type
662: convertedValue = value;
663: }
664: return convertedValue;
665: }
666:
667: private static String getValueClass(Object value) {
668: return value != null ? value.getClass().toString() : "null";
669: }
670:
671: }