com.modusoperandi.dragonfly.widgets.map.MapSettingsPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.modusoperandi.dragonfly.widgets.map.MapSettingsPanel.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.map;

import com.carrotsearch.hppc.ObjectLookupContainer;
import com.google.common.collect.UnmodifiableIterator;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
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.form.TextField;
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 MapSettingsPanel extends Panel {

    private transient static Client esClient = null;
    private static final String GEO_JSON = "GeoJSON";
    private static final String HEAT_MAP = "Query Results";
    private static final Logger LOGGER = Logger.getLogger(MapSettingsPanel.class.getName());
    private static final long serialVersionUID = 1L;
    private static final String WMS = "WMS";

    /**
     * Csv to list.
     * 
     * This converts a comma separated value list to a list of strings Any "," or "\" that should appear in the data
     * results (i.e. is not a separator or escape char) should be preceeded by a "\" (@see listToCsv)
     * 
     * @param csv
     *            the csv created by or in comformance with listToCsv()
     * @param stingList
     *            a list of string to encode
     */
    public static void csvToList(final String csv, final List<String> stingList) {

        byte[] headerCsv;
        try {
            headerCsv = csv.getBytes("UTF-8");
            final StringBuffer buffer = new StringBuffer();

            boolean insideQuotes = false;
            for (int i = 0; i < headerCsv.length; i++) {
                if (headerCsv[i] == '\\') {
                    // Next char was escaped
                    i++;

                    if (i < headerCsv.length) {
                        buffer.append((char) headerCsv[i]);
                    }

                } else if (headerCsv[i] == '\"') {
                    insideQuotes = !insideQuotes;

                } else if (!insideQuotes && (headerCsv[i] == ',')) {
                    // Seperator
                    stingList.add(buffer.toString());

                    buffer.setLength(0);

                } else {
                    buffer.append((char) headerCsv[i]);
                }
            }

            stingList.add(buffer.toString());

        } catch (final UnsupportedEncodingException e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    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 String geojson;
    private WebMarkupContainer geojsonDiv;
    private DropDownChoice<?> geojsonField;
    private WebMarkupContainer heatmapDiv;
    private String hmLocation;
    private DropDownChoice<?> hmLocationField;
    private String hmRadius;
    private String hmTransparency;
    private final WebMarkupContainer indexDiv;
    private final List<String> indexList = new LinkedList<>();
    private String indexName;
    private final List<String> locationFieldList = new LinkedList<>();
    private boolean ok = false;
    private DropDownChoice<?> selectHmRadius;
    private DropDownChoice<?> selectHmTransparency;
    private final DropDownChoice<?> selectIndex;
    private final List<String> stringFieldList = new LinkedList<>();
    private String tileUrl;
    private TextField<String> tileUrlField;
    private String type = HEAT_MAP;
    private String wmsAttribution;
    private TextField<String> wmsAttributionField;
    private WebMarkupContainer wmsDiv;
    private String wmsFormat;
    private TextField<String> wmsFormatField;
    private String wmsLayers;
    private TextField<String> wmsLayersField;
    private String wmsName;
    private TextField<String> wmsNameField;
    private String wmsPreset;
    private DropDownChoice<?> wmsPresetField;
    private final List<String> wmsPresetList = new LinkedList<>();
    private final Map<String, Map<String, String>> wmsPresets = new HashMap<>();

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

        super(id);

        populateWmsPresetList();

        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[] { HEAT_MAP, GEO_JSON, WMS })) {

            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);
                target.add(heatmapDiv);
                target.add(geojsonDiv);
                target.add(wmsDiv);
            }

        });
        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.setOutputMarkupId(true);
        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(locationFieldList, "geo_point");
                if (locationFieldList.size() > 0) {
                    hmLocation = locationFieldList.get(0);
                }

                populateFieldsList(stringFieldList, "string");
                if (stringFieldList.size() > 0) {
                    geojson = stringFieldList.get(0);
                }

                target.add(geojsonField);
                target.add(hmLocationField);
            }
        });
        indexDiv.add(selectIndex);

        // ////////////////////////////
        // Type Panels

        configureHeatmapDiv();
        configureGeojsonDiv();
        configureWmsDiv();

        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();

                switch (type) {
                case HEAT_MAP:
                    configuration.put("Type", HEAT_MAP);
                    configuration.put("Index", indexName);
                    configuration.put("Location", hmLocation);
                    configuration.put("HmTransparency", hmTransparency);
                    configuration.put("HmRadius", hmRadius);
                    break;

                case GEO_JSON:
                    configuration.put("Type", GEO_JSON);
                    configuration.put("Index", indexName);
                    configuration.put("GeojsonField", geojson);
                    break;

                case WMS:
                    configuration.put("Type", WMS);
                    configuration.put("TileURL", tileUrl);
                    configuration.put("Name", wmsName);
                    configuration.put("Format", wmsFormat);
                    configuration.put("Attribution", wmsAttribution);
                    configuration.put("Layers", wmsLayers);
                    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 configureGeojsonDiv() {

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

        geojsonField = new DropDownChoice<>("geojson", new PropertyModel<String>(this, "geojson"), stringFieldList);
        geojsonField.setOutputMarkupId(true);
        geojsonDiv.add(geojsonField);
    }

    private void configureHeatmapDiv() {

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

        hmLocationField = new DropDownChoice<>("hmlocation", new PropertyModel<String>(this, "hmLocation"),
                locationFieldList);
        hmLocationField.setOutputMarkupId(true);
        heatmapDiv.add(hmLocationField);

        hmTransparency = ".5";
        selectHmTransparency = new DropDownChoice<>("hmtransparency",
                new PropertyModel<String>(this, "hmTransparency"),
                Arrays.asList(new String[] { ".1", ".3", ".5", ".7", ".9" }));
        heatmapDiv.add(selectHmTransparency);

        hmRadius = "20";
        selectHmRadius = new DropDownChoice<>("hmradius", new PropertyModel<String>(this, "hmRadius"),
                Arrays.asList(new String[] { "5", "10", "20", "30", "50" }));
        heatmapDiv.add(selectHmRadius);
    }

    private void configureWmsDiv() {

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

        wmsPresetField = new DropDownChoice<>("wmsPreset", new PropertyModel<String>(this, "wmsPreset"),
                wmsPresetList);
        wmsPresetField.setOutputMarkupId(true);
        wmsPresetField.add(new AjaxFormComponentUpdatingBehavior("change") {

            private static final long serialVersionUID = 2981822623630720652L;

            @Override
            protected void onUpdate(final AjaxRequestTarget target) {

                final Map<String, String> entry = wmsPresets.get(wmsPreset);

                if (entry != null) {
                    tileUrl = entry.get("Tile URL");
                    wmsName = entry.get("Name");
                    wmsLayers = entry.get("Layers");
                    wmsFormat = entry.get("Format");
                    wmsAttribution = entry.get("Attribution");
                }

                target.add(tileUrlField);
                target.add(wmsNameField);
                target.add(wmsLayersField);
                target.add(wmsFormatField);
                target.add(wmsAttributionField);
            }
        });
        indexDiv.add(selectIndex);

        wmsDiv.add(wmsPresetField);

        tileUrlField = new TextField<>("tileUrl", new PropertyModel<>(this, "tileUrl"));
        tileUrlField.setOutputMarkupId(true);
        wmsDiv.add(tileUrlField);

        wmsNameField = new TextField<>("wmsName", new PropertyModel<>(this, "wmsName"));
        wmsNameField.setOutputMarkupId(true);
        wmsDiv.add(wmsNameField);

        wmsLayersField = new TextField<>("wmsLayers", new PropertyModel<>(this, "wmsLayers"));
        wmsLayersField.setOutputMarkupId(true);
        wmsDiv.add(wmsLayersField);

        wmsFormatField = new TextField<>("wmsFormat", new PropertyModel<>(this, "wmsFormat"));
        wmsFormatField.setOutputMarkupId(true);
        wmsDiv.add(wmsFormatField);

        wmsAttributionField = new TextField<>("wmsAttribution", new PropertyModel<>(this, "wmsAttribution"));
        wmsAttributionField.setOutputMarkupId(true);
        wmsDiv.add(wmsAttributionField);
    }

    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();

                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 populateWmsPresetList() {

        BufferedReader fileReader = null;

        try {
            String line;

            // Create the file reader
            fileReader = new BufferedReader(new FileReader("dragonfly/DragonflyWms.csv"));

            // Read the file line by line
            boolean firstLine = true;
            final List<String> columnHeaders = new LinkedList<>();
            while ((line = fileReader.readLine()) != null) {
                if (firstLine) {
                    firstLine = false;
                    csvToList(line, columnHeaders);

                } else {
                    // Get all tokens available in line
                    final List<String> tokens = new LinkedList<>();
                    csvToList(line, tokens);

                    final Map<String, String> data = new HashMap<>();

                    for (int i = 0; (i < columnHeaders.size()) && (i < tokens.size()); i++) {

                        data.put(columnHeaders.get(i), tokens.get(i));
                    }

                    wmsPresetList.add(data.get("Name"));
                    wmsPresets.put(data.get("Name"), data);
                }
            }

            try {
                fileReader.close();
            } catch (final IOException e1) {
                LOGGER.log(Level.SEVERE, e1.getMessage(), e1);
            }
        } catch (final FileNotFoundException e) {
            // No file so there's nothing to do

        } catch (final IOException e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (final IOException e1) {
                    LOGGER.log(Level.SEVERE, e1.getMessage(), e1);
                }
            }
        }
    }

    private void showDivs() {

        switch (type) {
        case HEAT_MAP:
            indexDiv.setVisible(true);
            heatmapDiv.setVisible(true);
            geojsonDiv.setVisible(false);
            wmsDiv.setVisible(false);
            break;

        case GEO_JSON:
            indexDiv.setVisible(true);
            heatmapDiv.setVisible(false);
            geojsonDiv.setVisible(true);
            wmsDiv.setVisible(false);
            break;

        case WMS:
            indexDiv.setVisible(false);
            heatmapDiv.setVisible(false);
            geojsonDiv.setVisible(false);
            wmsDiv.setVisible(true);
            break;
        }
    }
}