org.graylog2.restclient.models.api.results.MessageResult.java Source code

Java tutorial

Introduction

Here is the source code for org.graylog2.restclient.models.api.results.MessageResult.java

Source

/**
 * This file is part of Graylog.
 *
 * Graylog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Graylog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Graylog.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.graylog2.restclient.models.api.results;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import org.graylog2.restclient.models.FieldMapper;
import org.graylog2.restclient.models.api.responses.HighlightRange;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import javax.annotation.Nullable;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class MessageResult {
    private final static Set<String> HIDDEN_FIELDS = ImmutableSet.of("_id", "timestamp", "streams",
            "gl2_source_input", "gl2_source_node", "gl2_source_radio", "gl2_source_radio_input",
            "gl2_source_collector", "gl2_source_collector_input", "g2eid");

    private final Map<String, Object> fields;
    private final String index;
    private final String id;
    private final DateTime timestamp;
    private final String sourceNodeId;
    private final String sourceInputId;
    private final String sourceRadioId;
    private final String sourceRadioInputId;
    private final List<String> streamIds;
    private final Map<String, List<HighlightRange>> highlightRanges;
    private final FieldMapper fieldMapper;

    public MessageResult(Map<String, Object> message, String index,
            Map<String, List<HighlightRange>> highlightRanges, FieldMapper fieldMapper) {
        this.highlightRanges = highlightRanges;
        this.fieldMapper = fieldMapper;
        // this comparator sorts fields alphabetically, but always leaves full_message at the end.
        // it really is interface, but I don't want to put it into the template either.
        // doing it here also means we don't have to copy the entire map when sorting...
        fields = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String left, String right) {
                // full_message is always "larger" than anything else, except itself
                final boolean rightIsFullMessage = right.equals("full_message");
                final boolean leftisFullMessage = left.equals("full_message");
                if (leftisFullMessage) {
                    if (rightIsFullMessage) {
                        return 0; // SAME
                    } else {
                        return 1; // LEFT is larger
                    }
                } else {
                    if (rightIsFullMessage) {
                        return -1; // RIGHT is larger
                    }
                }
                return left.compareTo(right);
            }
        });

        fields.putAll(message);

        this.id = (String) message.get("_id");
        this.timestamp = timestampToDateTime(message.get("timestamp"));
        this.sourceNodeId = (String) message.get("gl2_source_node");
        this.sourceInputId = (String) message.get("gl2_source_input");
        this.index = index;
        this.streamIds = (List<String>) message.get("streams");

        if (message.containsKey("gl2_source_radio")) {
            sourceRadioId = (String) message.get("gl2_source_radio");
            sourceRadioInputId = (String) message.get("gl2_source_radio_input");
        } else {
            sourceRadioId = null;
            sourceRadioInputId = null;
        }
    }

    private DateTime timestampToDateTime(final Object timestamp) {
        if (timestamp instanceof Double) {
            return new DateTime(Math.round((double) timestamp * 1000.0d), DateTimeZone.UTC);
        } else if (timestamp instanceof Long || timestamp instanceof Integer) {
            return new DateTime((long) timestamp * 1000L, DateTimeZone.UTC);
        } else {
            return new DateTime(timestamp, DateTimeZone.UTC);
        }
    }

    public String getId() {
        return id;
    }

    public DateTime getTimestamp() {
        return timestamp;
    }

    public Map<String, Object> getFilteredFields() {
        // return a _view_ of the fields map, do not make a copy, because subsequent manipulation would get lost!
        return Maps.filterEntries(getFields(), new Predicate<Map.Entry<String, Object>>() {
            @Override
            public boolean apply(@Nullable Map.Entry<String, Object> input) {
                return input != null && !HIDDEN_FIELDS.contains(input.getKey());
            }
        });
    }

    public Map<String, Object> getFields() {
        return fields;
    }

    public Map<String, Object> getFormattedFields() {
        final DecimalFormat doubleFormatter = new DecimalFormat("#.###");

        return Maps.transformEntries(getFilteredFields(), new Maps.EntryTransformer<String, Object, Object>() {
            @Override
            public Object transformEntry(@Nullable String key, @Nullable Object value) {
                // Get rid of .0 of doubles. 9001.0 becomes "9001", 9001.25 becomes "9001.25"
                // Never format a double in scientific notation.
                if (value instanceof Double) {
                    Double d = (Double) value;
                    if (d.longValue() == d) {
                        // preserve the "numberness" of the value, so the field mappers can take this into account
                        // basically wait with stringification until the last moment in the template
                        value = d.longValue();
                    } else {
                        value = doubleFormatter.format(d);
                    }
                }
                return fieldMapper.map(key, value);
            }
        });
    }

    public String getIndex() {
        return index;
    }

    public String getSourceNodeId() {
        return sourceNodeId;
    }

    public String getSourceInputId() {
        return sourceInputId;
    }

    public boolean viaRadio() {
        return sourceRadioId != null;
    }

    public String getSourceRadioId() {
        return sourceRadioId;
    }

    public String getSourceRadioInputId() {
        return sourceRadioInputId;
    }

    public List<String> getStreamIds() {
        if (this.streamIds != null) {
            return this.streamIds;
        } else {
            return Collections.emptyList();
        }
    }

    public Map<String, List<HighlightRange>> getHighlightRanges() {
        return highlightRanges;
    }

    public boolean hasHighlightedField(String field) {
        return highlightRanges != null && highlightRanges.containsKey(field);
    }

    public HighlightedField getHighlightedField(String field) {
        return new HighlightedField(this, field);
    }
}