com.modusoperandi.dragonfly.widgets.chart.SettingsPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.modusoperandi.dragonfly.widgets.chart.SettingsPanel.java

Source

/**
 * Copyright (c) 2016 Modus Operandi, Inc.
 *
 * This is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or any later version.
 *
 * This program 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 Lesser General Public License for more
 * details. A copy of the GNU Lesser General Public License is distributed along
 * with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package com.modusoperandi.dragonfly.widgets.chart;

import com.carrotsearch.hppc.ObjectLookupContainer;
import com.google.common.collect.UnmodifiableIterator;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RadioChoice;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;

/**
 * The Class HeatMapSettingsPanel - Supports adding and removing data
 */
public class SettingsPanel extends Panel {

    public static final String XY = "X/Y";
    public static final String FACET_BAR = "Occurance";
    public static final String SERIES_LINE = "Series";
    public static final String FACET_PIE = "Pie";
    public static final String TIMEWHEEL = "Time Wheel";
    public static final String HEAT_MAP_RING_MAP = "Heat Map Ring Map";

    private static final Logger LOGGER = Logger.getLogger(SettingsPanel.class.getName());
    private static transient Client esClient = null;
    private static final long serialVersionUID = 1L;

    private static ImmutableOpenMap<String, MappingMetaData> esGetMappings(final String indexName) {

        final ClusterStateResponse clusterStateResponse = getEsClient().admin().cluster().prepareState().execute()
                .actionGet();

        return clusterStateResponse.getState().getMetaData().index(indexName).getMappings();
    }

    /**
     * Gets the Elasticsearch client.
     *
     * @return the Elasticsearch client
     */
    private static Client getEsClient() {

        // ////////////
        // Remote
        if (esClient == null) {
            try {
                final Settings settings = Settings.settingsBuilder()
                        .put("node.name", "DRAGONFLY_" + Long.toString(Thread.currentThread().getId()))
                        .put("cluster.name", "DRAGONFLY").build();
                esClient = new TransportClient.Builder().settings(settings).build().addTransportAddress(
                        new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
            } catch (UnknownHostException ex) {
                LOGGER.log(Level.SEVERE, null, ex);
            }
        }

        return esClient;
    }

    private Map<String, String> configuration;
    private WebMarkupContainer contentDiv;
    private final WebMarkupContainer indexDiv;
    private final List<String> indexList = new LinkedList<>();
    private String indexName;
    private final List<String> numericFieldsList = new LinkedList<>();
    private final List<String> allFieldsList = new LinkedList<>();
    private final List<String> timeFieldsList = new LinkedList<>();
    private final List<String> locationFieldsList = new LinkedList<>();
    private boolean ok = false;
    private final DropDownChoice<?> selectIndex;
    private String type = XY;
    private String xField;
    private DropDownChoice<?> xSelectField;
    private DropDownChoice<?> countSelectField;
    private DropDownChoice<?> pieCountSelectField;
    private DropDownChoice<?> maxItemsField;
    private DropDownChoice<?> pieMaxItemsField;
    private WebMarkupContainer xyDiv;
    private String yField;
    private DropDownChoice<?> ySelectField;
    private String countField;
    private String pieCountField;
    private WebMarkupContainer facetBarDiv;
    private WebMarkupContainer facetPieDiv;
    private String maxItems = "20";
    private String pieMaxItems = "20";
    private String seriesXField;
    private DropDownChoice<?> seriesXSelectField;
    private String seriesYField;
    private DropDownChoice<?> seriesYSelectField;
    private WebMarkupContainer seriesDiv;
    private String twTimeField;
    private String twTimeScaleField = "Days/Hours";
    private DropDownChoice<?> twTimeScaleSelectField;
    private DropDownChoice<?> twTimeSelectField;
    private DropDownChoice<?> twContrastScaleSelectField;
    private String twContrastScaleField = "0";
    private WebMarkupContainer timewheelDiv;
    private WebMarkupContainer hmrmDiv;
    private String hmrmTimeField;
    private String hmrmTimeScaleField = "Years";
    private DropDownChoice<?> hmrmTimeScaleSelectField;
    private DropDownChoice<?> hmrmTimeSelectField;
    private DropDownChoice<?> hmrmLocationSelectField;
    private String hmrmLocationField;
    private DropDownChoice<?> hmrmLabelSelectField;
    private String hmrmLabelField;

    /**
     * Instantiates a new settings page.
     *
     * @param id
     * @param modalWindow
     */
    public SettingsPanel(final String id, final ModalWindow modalWindow) {

        super(id);

        configuration = new HashMap<>();

        final Form<?> dataForm = new Form<>("dataForm");
        add(dataForm);

        contentDiv = new WebMarkupContainer("contentDiv");
        contentDiv.setOutputMarkupId(true);
        dataForm.add(contentDiv);

        // ////////////////////////////
        // Type
        final RadioChoice<String> typeField = new RadioChoice<String>("type", new PropertyModel<>(this, "type"),
                Arrays.asList(
                        new String[] { XY, FACET_BAR, SERIES_LINE, FACET_PIE, TIMEWHEEL, HEAT_MAP_RING_MAP })) {

            private static final long serialVersionUID = 1L;

            @Override
            public String getSuffix() {

                return "";
            }
        };

        typeField.add(new AjaxFormChoiceComponentUpdatingBehavior() {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {

                type = getComponent().getDefaultModelObjectAsString();

                showDivs();

                target.add(contentDiv);
            }

        });
        contentDiv.add(typeField);

        // ////////////////////////////
        // Index Name
        populateIndices();

        indexDiv = new WebMarkupContainer("indexDiv");
        indexDiv.setOutputMarkupId(true);
        contentDiv.add(indexDiv);

        selectIndex = new DropDownChoice<>("dataSet", new PropertyModel<String>(this, "indexName"), indexList);
        selectIndex.add(new AjaxFormComponentUpdatingBehavior("focus") {

            private static final long serialVersionUID = 2981822623630720652L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {

                if (populateIndices()) {
                    target.add(selectIndex);
                }
            }
        });
        selectIndex.add(new AjaxFormComponentUpdatingBehavior("change") {

            private static final long serialVersionUID = 2981822623630720652L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {

                populateFieldsList(numericFieldsList, "double");
                populateFieldsList(allFieldsList, null);
                populateFieldsList(timeFieldsList, "date");
                populateFieldsList(locationFieldsList, "geo_point");

                if (numericFieldsList.size() > 0) {

                    seriesYField = numericFieldsList.get(0);

                    xField = numericFieldsList.get(0);
                    yField = numericFieldsList.get(0);
                }

                if (allFieldsList.size() > 0) {

                    countField = allFieldsList.get(0);

                    pieCountField = allFieldsList.get(0);

                    seriesXField = allFieldsList.get(0);

                    hmrmLabelField = allFieldsList.get(0);
                }

                if (timeFieldsList.size() > 0) {

                    twTimeField = timeFieldsList.get(0);

                    hmrmTimeField = timeFieldsList.get(0);
                }

                if (locationFieldsList.size() > 0) {

                    hmrmLocationField = locationFieldsList.get(0);
                }

                target.add(xSelectField);
                target.add(ySelectField);
                target.add(countSelectField);
                target.add(seriesXSelectField);
                target.add(seriesYSelectField);
                target.add(pieCountSelectField);
                target.add(twTimeSelectField);
                target.add(hmrmTimeSelectField);
                target.add(hmrmLocationSelectField);
                target.add(hmrmLabelSelectField);
            }
        });
        indexDiv.add(selectIndex);

        // ////////////////////////////
        // Type Panels
        configureXyDiv();
        configureFacetBarDiv();
        configureSeriesDiv();
        configureFacetPieDiv();
        configureTimewheelDiv();
        configureHeatMapRingMapDiv();

        showDivs();

        // ////////////////////////////
        // Buttons
        dataForm.add(new AjaxButton("okButton") {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {

                configuration.clear();

                configuration.put("Index", indexName);
                configuration.put("Type", type);

                switch (type) {
                case XY:
                    configuration.put("X", xField);
                    configuration.put("Y", yField);
                    break;

                case FACET_BAR:
                    configuration.put("CountField", countField);
                    configuration.put("MaxItems", maxItems);
                    break;

                case SERIES_LINE:
                    configuration.put("X", seriesXField);
                    configuration.put("Y", seriesYField);
                    break;

                case FACET_PIE:
                    configuration.put("CountField", pieCountField);
                    configuration.put("MaxItems", pieMaxItems);
                    break;

                case TIMEWHEEL:
                    configuration.put("TimeScale", twTimeScaleField);
                    configuration.put("TimeField", twTimeField);
                    configuration.put("ContrastScale", twContrastScaleField);
                    break;

                case HEAT_MAP_RING_MAP:
                    configuration.put("TimeScale", hmrmTimeScaleField);
                    configuration.put("TimeField", hmrmTimeField);
                    configuration.put("LocationField", hmrmLocationField);
                    configuration.put("LabelField", hmrmLabelField);
                    break;
                }

                ok = true;
                modalWindow.close(target);
            }
        });

        dataForm.add(new AjaxButton("cancelButton") {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {

                configuration.clear();

                ok = false;
                modalWindow.close(target);
            }
        });
    }

    public Map<String, String> getConfiguration() {

        return configuration;
    }

    public boolean isOk() {

        return ok;
    }

    private void configureXyDiv() {

        xyDiv = new WebMarkupContainer("xyDiv");
        xyDiv.setOutputMarkupId(true);
        contentDiv.add(xyDiv);

        xSelectField = new DropDownChoice<>("xField", new PropertyModel<String>(this, "xField"), numericFieldsList);
        xSelectField.setOutputMarkupId(true);
        xyDiv.add(xSelectField);

        ySelectField = new DropDownChoice<>("yField", new PropertyModel<String>(this, "yField"), numericFieldsList);
        ySelectField.setOutputMarkupId(true);
        xyDiv.add(ySelectField);
    }

    private void configureSeriesDiv() {

        seriesDiv = new WebMarkupContainer("seriesDiv");
        seriesDiv.setOutputMarkupId(true);
        contentDiv.add(seriesDiv);

        seriesXSelectField = new DropDownChoice<>("seriesXField", new PropertyModel<String>(this, "seriesXField"),
                timeFieldsList);
        seriesXSelectField.setOutputMarkupId(true);
        seriesDiv.add(seriesXSelectField);

        seriesYSelectField = new DropDownChoice<>("seriesYField", new PropertyModel<String>(this, "seriesYField"),
                numericFieldsList);
        seriesYSelectField.setOutputMarkupId(true);
        seriesDiv.add(seriesYSelectField);
    }

    private void configureFacetBarDiv() {

        facetBarDiv = new WebMarkupContainer("facetBarDiv");
        facetBarDiv.setOutputMarkupId(true);
        contentDiv.add(facetBarDiv);

        countSelectField = new DropDownChoice<>("countField", new PropertyModel<String>(this, "countField"),
                allFieldsList);
        countSelectField.setOutputMarkupId(true);
        facetBarDiv.add(countSelectField);

        maxItemsField = new DropDownChoice<>("maxItems", new PropertyModel<String>(this, "maxItems"),
                Arrays.asList(new String[] { "5", "10", "20", "50" }));
        maxItemsField.setOutputMarkupId(true);
        facetBarDiv.add(maxItemsField);
    }

    private void configureFacetPieDiv() {

        facetPieDiv = new WebMarkupContainer("facetPieDiv");
        facetPieDiv.setOutputMarkupId(true);
        contentDiv.add(facetPieDiv);

        pieCountSelectField = new DropDownChoice<>("pieCountField",
                new PropertyModel<String>(this, "pieCountField"), allFieldsList);
        pieCountSelectField.setOutputMarkupId(true);
        facetPieDiv.add(pieCountSelectField);

        pieMaxItemsField = new DropDownChoice<>("pieMaxItems", new PropertyModel<String>(this, "pieMaxItems"),
                Arrays.asList(new String[] { "5", "10", "20", "50" }));
        pieMaxItemsField.setOutputMarkupId(true);
        facetPieDiv.add(pieMaxItemsField);
    }

    private void configureTimewheelDiv() {

        timewheelDiv = new WebMarkupContainer("timewheelDiv");
        timewheelDiv.setOutputMarkupId(true);
        contentDiv.add(timewheelDiv);

        twTimeScaleSelectField = new DropDownChoice<>("twTimeScaleField",
                new PropertyModel<String>(this, "twTimeScaleField"),
                Arrays.asList(new String[] { "Days/Hours", "Months/Days" }));
        timewheelDiv.add(twTimeScaleSelectField);

        twTimeSelectField = new DropDownChoice<>("twTimeField", new PropertyModel<String>(this, "twTimeField"),
                timeFieldsList);
        twTimeSelectField.setOutputMarkupId(true);
        timewheelDiv.add(twTimeSelectField);

        twContrastScaleSelectField = new DropDownChoice<>("twContrastScaleField",
                new PropertyModel<String>(this, "twContrastScaleField"), Arrays.asList(
                        new String[] { "-90%", "-75%", "-50%", "-25%", "0", "+25%", "+50%", "+75%", "+90%" }));
        timewheelDiv.add(twContrastScaleSelectField);
    }

    private void configureHeatMapRingMapDiv() {

        hmrmDiv = new WebMarkupContainer("heatMapRingMapDiv");
        hmrmDiv.setOutputMarkupId(true);
        contentDiv.add(hmrmDiv);

        hmrmTimeScaleSelectField = new DropDownChoice<>("hmrmTimeScaleField",
                new PropertyModel<String>(this, "hmrmTimeScaleField"),
                Arrays.asList(new String[] { "Years", "Months", "Days", "Hours", "Minutes" }));

        hmrmDiv.add(hmrmTimeScaleSelectField);

        hmrmTimeSelectField = new DropDownChoice<>("hmrmTimeField",
                new PropertyModel<String>(this, "hmrmTimeField"), timeFieldsList);
        hmrmTimeSelectField.setOutputMarkupId(true);
        hmrmDiv.add(hmrmTimeSelectField);

        hmrmLocationSelectField = new DropDownChoice<>("hmrmLocationField",
                new PropertyModel<String>(this, "hmrmLocationField"), locationFieldsList);
        hmrmLocationSelectField.setOutputMarkupId(true);
        hmrmDiv.add(hmrmLocationSelectField);

        hmrmLabelSelectField = new DropDownChoice<>("hmrmLabelField",
                new PropertyModel<String>(this, "hmrmLabelField"), allFieldsList);
        hmrmLabelSelectField.setOutputMarkupId(true);
        hmrmDiv.add(hmrmLabelSelectField);
    }

    private SearchResponse esMakeQuery() {

        final SearchRequestBuilder search = getEsClient().prepareSearch(indexName);
        search.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);

        return search.execute().actionGet();
    }

    /**
     * Populate field lists from the ES index mapping.
     */
    private void populateFieldsList(final List<String> list, final String desiredType) {

        list.clear();

        try {
            esMakeQuery();

            final ImmutableOpenMap<String, MappingMetaData> typeMappings = esGetMappings(indexName);

            final UnmodifiableIterator<MappingMetaData> it = typeMappings.valuesIt();
            while (it.hasNext()) {
                final MappingMetaData mapping = it.next();

                @SuppressWarnings("unchecked")
                final Map<String, Object> fields = ((Map<String, Object>) mapping.getSourceAsMap()
                        .get("properties"));
                fields.keySet().stream().forEach((y) -> {
                    @SuppressWarnings("unchecked")
                    final String fieldType = ((Map<String, Object>) fields.get(y)).get("type").toString();
                    if ((desiredType == null) || fieldType.equals(desiredType)) {
                        list.add(y);
                    }
                });
            }
        } catch (final IOException e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    private boolean populateIndices() {

        ObjectLookupContainer<String> mapAl = getEsClient().admin().cluster().prepareState().execute().actionGet()
                .getState().getMetaData().indices().keys();
        final Object keyAry[] = mapAl.toArray();

        boolean changed = (indexList.size() != keyAry.length);
        int i = 0;
        while ((i < indexList.size()) && (i < keyAry.length) && !changed) {
            changed = !indexList.get(i).equals(keyAry[i]);
            i++;
        }

        if (changed) {
            indexList.clear();
            for (final Object index : keyAry) {
                indexList.add(index.toString());
            }
        }

        return changed;
    }

    private void showDivs() {

        switch (type) {
        case XY:
            indexDiv.setVisible(true);
            xyDiv.setVisible(true);
            facetBarDiv.setVisible(false);
            seriesDiv.setVisible(false);
            facetPieDiv.setVisible(false);
            timewheelDiv.setVisible(false);
            hmrmDiv.setVisible(false);
            break;

        case FACET_BAR:
            indexDiv.setVisible(true);
            xyDiv.setVisible(false);
            facetBarDiv.setVisible(true);
            seriesDiv.setVisible(false);
            facetPieDiv.setVisible(false);
            timewheelDiv.setVisible(false);
            hmrmDiv.setVisible(false);
            break;

        case SERIES_LINE:
            indexDiv.setVisible(true);
            xyDiv.setVisible(false);
            facetBarDiv.setVisible(false);
            seriesDiv.setVisible(true);
            facetPieDiv.setVisible(false);
            timewheelDiv.setVisible(false);
            hmrmDiv.setVisible(false);
            break;

        case FACET_PIE:
            indexDiv.setVisible(true);
            xyDiv.setVisible(false);
            facetBarDiv.setVisible(false);
            seriesDiv.setVisible(false);
            facetPieDiv.setVisible(true);
            timewheelDiv.setVisible(false);
            hmrmDiv.setVisible(false);
            break;

        case TIMEWHEEL:
            indexDiv.setVisible(true);
            xyDiv.setVisible(false);
            facetBarDiv.setVisible(false);
            seriesDiv.setVisible(false);
            facetPieDiv.setVisible(false);
            timewheelDiv.setVisible(true);
            hmrmDiv.setVisible(false);
            break;

        case HEAT_MAP_RING_MAP:
            indexDiv.setVisible(true);
            xyDiv.setVisible(false);
            facetBarDiv.setVisible(false);
            seriesDiv.setVisible(false);
            facetPieDiv.setVisible(false);
            timewheelDiv.setVisible(false);
            hmrmDiv.setVisible(true);
            break;
        }
    }
}