Java tutorial
/** * 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; } } }