001/*******************************************************************************
002 * Copyright (c) 2017 Red Hat Inc and others
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Red Hat Inc - initial API and implementation
011 *******************************************************************************/
012package org.eclipse.kapua.gateway.client.kura.internal;
013
014import java.nio.ByteBuffer;
015import java.util.List;
016import java.util.Map;
017import java.util.Objects;
018import java.util.TreeMap;
019
020import org.eclipse.kapua.gateway.client.kura.payload.KuraPayloadProto.KuraPayload;
021import org.eclipse.kapua.gateway.client.kura.payload.KuraPayloadProto.KuraPayload.KuraMetric;
022import org.eclipse.kapua.gateway.client.kura.payload.KuraPayloadProto.KuraPayload.KuraMetric.ValueType;
023
024import com.google.protobuf.ByteString;
025
026public final class Metrics {
027
028    private Metrics() {
029    }
030
031    /**
032     * Convert plain key value map into a Kura metric structure <br>
033     * Only the supported Kura values types must be used (String, boolean, int,
034     * long, float, double, byte[])
035     *
036     * @param builder
037     *            the builder to append the metrics to
038     * @param metrics
039     *            the metrics map
040     * @throws IllegalArgumentException
041     *             in case of an unsupported value type
042     */
043    public static void buildMetrics(final KuraPayload.Builder builder, final Map<String, ?> metrics) {
044        Objects.requireNonNull(metrics);
045
046        for (final Map.Entry<String, ?> metric : metrics.entrySet()) {
047            addMetric(builder, metric.getKey(), metric.getValue());
048        }
049    }
050
051    public static void buildBody(final KuraPayload.Builder builder, final ByteBuffer body) {
052        if (body == null) {
053            return;
054        }
055
056        Objects.requireNonNull(builder);
057
058        builder.setBody(ByteString.copyFrom(body));
059    }
060
061    public static void addMetric(final KuraPayload.Builder builder, final String key, final Object value) {
062        final KuraMetric.Builder b = KuraMetric.newBuilder();
063        b.setName(key);
064
065        if (value == null) {
066            return;
067        } else if (value instanceof Boolean) {
068            b.setType(ValueType.BOOL);
069            b.setBoolValue((boolean) value);
070        } else if (value instanceof Integer) {
071            b.setType(ValueType.INT32);
072            b.setIntValue((int) value);
073        } else if (value instanceof String) {
074            b.setType(ValueType.STRING);
075            b.setStringValue((String) value);
076        } else if (value instanceof Long) {
077            b.setType(ValueType.INT64);
078            b.setLongValue((Long) value);
079        } else if (value instanceof Double) {
080            b.setType(ValueType.DOUBLE);
081            b.setDoubleValue((Double) value);
082        } else if (value instanceof Float) {
083            b.setType(ValueType.FLOAT);
084            b.setFloatValue((Float) value);
085        } else if (value instanceof byte[]) {
086            b.setType(ValueType.BYTES);
087            b.setBytesValue(ByteString.copyFrom((byte[]) value));
088        } else {
089            throw new IllegalArgumentException(String.format("Illegal metric data type: %s", value.getClass()));
090        }
091
092        builder.addMetric(b);
093    }
094
095    public static Map<String, Object> extractMetrics(final KuraPayload payload) {
096        if (payload == null) {
097            return null;
098        }
099        return extractMetrics(payload.getMetricList());
100    }
101
102    public static Map<String, Object> extractMetrics(final List<KuraMetric> metricList) {
103        if (metricList == null) {
104            return null;
105        }
106
107        /*
108         * We are using a TreeMap in order to have a stable order of properties
109         */
110        final Map<String, Object> result = new TreeMap<>();
111
112        for (final KuraMetric metric : metricList) {
113            final String name = metric.getName();
114            switch (metric.getType()) {
115            case BOOL:
116                result.put(name, metric.getBoolValue());
117                break;
118            case BYTES:
119                result.put(name, metric.getBytesValue().toByteArray());
120                break;
121            case DOUBLE:
122                result.put(name, metric.getDoubleValue());
123                break;
124            case FLOAT:
125                result.put(name, metric.getFloatValue());
126                break;
127            case INT32:
128                result.put(name, metric.getIntValue());
129                break;
130            case INT64:
131                result.put(name, metric.getLongValue());
132                break;
133            case STRING:
134                result.put(name, metric.getStringValue());
135                break;
136            }
137        }
138
139        return result;
140    }
141
142    public static String getAsString(final Map<String, Object> metrics, final String key) {
143        return getAsString(metrics, key, null);
144    }
145
146    public static String getAsString(final Map<String, Object> metrics, final String key, final String defaultValue) {
147        final Object value = metrics.get(key);
148        if (value == null) {
149            return defaultValue;
150        }
151        if (value instanceof String) {
152            return (String) value;
153        }
154        return defaultValue;
155    }
156}