VisualizationService.java

/*
 * Copyright (c) 2002-2021, City of Paris
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice
 *     and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice
 *     and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * License 1.0
 */
package fr.paris.lutece.plugins.kibana.service;

import java.util.UUID;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class VisualizationService
{
    /**
     * create a standard visualisation object to fill
     * 
     * @param visualization
     *            visualisation
     */
    public static JSONObject getVisualizationObject( String strTitle, String strIdVisualization, String strIdIndexPattern, String queryFilter )
    {
        JSONObject visualizationJSON = new JSONObject( );
        JSONObject searchSourceJSON = new JSONObject( );
        searchSourceJSON.put( "searchSourceJSON", "{\\\"query\\\":{\\\"query\\\":\\\"" + queryFilter
                + "\\\",\\\"language\\\":\\\"kuery\\\"},\\\"filter\\\":[],\\\"indexRefName\\\":\\\"kibanaSavedObjectMeta.searchSourceJSON.index\\\"}" );
        JSONObject migrationVersion = new JSONObject( );
        migrationVersion.put( "visualization", "7.8.0" );
        JSONObject reference = new JSONObject( );
        reference.put( "id", strIdIndexPattern );
        reference.put( "name", "kibanaSavedObjectMeta.searchSourceJSON.index" );
        reference.put( "type", "index-pattern" );
        JSONArray references = new JSONArray( );
        references.add( reference );
        JSONObject attributes = new JSONObject( );
        attributes.put( "title", strTitle.replace( ".keyword", "" ) );
        attributes.put( "description", "" );
        attributes.put( "version", "1" );
        attributes.put( "kibanaSavedObjectMeta", searchSourceJSON );
        attributes.put( "uiStateJSON", "" );
        visualizationJSON.put( "attributes", attributes );
        visualizationJSON.put( "id", strIdVisualization );
        visualizationJSON.put( "migrationVersion", migrationVersion );
        visualizationJSON.accumulate( "references", references );
        visualizationJSON.put( "type", "visualization" );
        visualizationJSON.put( "updated_at", "2020-10-02T20:04:58.470Z" );
        visualizationJSON.put( "version", "Wzc4OTUsN10=" );
        return visualizationJSON;
    }

    /**
     * create datatable with top values of a field
     * 
     * @param visualization
     *            visualisation
     */
    public static void createDataTableTopValueVisualization( String strTitle, String strFieldName, String strIdVisualization, String strIdIndexPattern,
            String queryFilter )
    {
        JSONObject dataTable = getVisualizationObject( strTitle, strIdVisualization, strIdIndexPattern, queryFilter );
        String visState = "{\\\"title\\\":\\\"" + strTitle
                + "\\\",\\\"type\\\":\\\"table\\\",\\\"aggs\\\":[{\\\"id\\\":\\\"1\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"count\\\",\\\"params\\\":{\\\"customLabel\\\":\\\"Nombre de réponses\\\"},\\\"schema\\\":\\\"metric\\\"},{\\\"id\\\":\\\"2\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"terms\\\",\\\"params\\\":{\\\"field\\\":\\\""
                + strFieldName
                + "\\\",\\\"orderBy\\\":\\\"1\\\",\\\"order\\\":\\\"desc\\\",\\\"size\\\":500,\\\"otherBucket\\\":true,\\\"otherBucketLabel\\\":\\\"Autres\\\",\\\"missingBucket\\\":true,\\\"missingBucketLabel\\\":\\\"Inconnu\\\",\\\"customLabel\\\":\\\""
                + strTitle
                + "\\\"},\\\"schema\\\":\\\"bucket\\\"}],\\\"params\\\":{\\\"perPage\\\":500,\\\"showPartialRows\\\":true,\\\"showMetricsAtAllLevels\\\":false,\\\"sort\\\":{\\\"columnIndex\\\":null,\\\"direction\\\":null},\\\"showTotal\\\":true,\\\"totalFunc\\\":\\\"sum\\\",\\\"percentageCol\\\":\\\"Réponses\\\"}}";
        ( (JSONObject) dataTable.get( "attributes" ) ).put( "visState", visState );
        SavedObjectService.create( dataTable );
    }

    /**
     * create donut lens visualization
     * 
     * @param visualization
     *            visualisation
     */
    public static void createDonutLensVisualization( String strTitle, String strFieldName, String strIdVisualization, String strIdIndexPattern,
            String queryFilter )
    {
        String strGroupId = UUID.randomUUID( ).toString( );
        String strLayerId = UUID.randomUUID( ).toString( );
        String strColumnId = UUID.randomUUID( ).toString( );
        String strDonutObj = "{\"attributes\":{\"description\":\"\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"" + strLayerId
                + "\":{\"columnOrder\":[\"" + strGroupId + "\",\"" + strColumnId + "\"],\"columns\":{\"" + strGroupId
                + "\":{\"dataType\":\"string\",\"isBucketed\":true,\"label\":\"" + strTitle
                + "\",\"operationType\":\"terms\",\"params\":{\"orderBy\":{\"columnId\":\"" + strColumnId
                + "\",\"type\":\"column\"},\"orderDirection\":\"desc\",\"size\":50},\"scale\":\"ordinal\",\"sourceField\":\"" + strFieldName + "\"},\""
                + strColumnId
                + "\":{\"dataType\":\"number\",\"isBucketed\":false,\"label\":\"Count of records\",\"operationType\":\"count\",\"scale\":\"ratio\",\"sourceField\":\"Records\"}}}}}},\"filters\":[],\"query\":{\"language\":\"kuery\",\"query\":\""
                + queryFilter + "\"},\"visualization\":{\"layers\":[{\"categoryDisplay\":\"default\",\"groups\":[\"" + strGroupId + "\"],\"layerId\":\""
                + strLayerId + "\",\"legendDisplay\":\"show\",\"legendPosition\":\"right\",\"metric\":\"" + strColumnId
                + "\",\"nestedLegend\":false,\"numberDisplay\":\"percent\"}],\"shape\":\"donut\"}},\"title\":\"" + strTitle
                + "\",\"visualizationType\":\"lnsPie\"},\"id\":\"" + strIdVisualization
                + "\",\"migrationVersion\":{\"lens\":\"7.10.0\"},\"references\":[{\"id\":\"" + strIdIndexPattern
                + "\",\"name\":\"indexpattern-datasource-current-indexpattern\",\"type\":\"index-pattern\"},{\"id\":\"" + strIdIndexPattern
                + "\",\"name\":\"indexpattern-datasource-layer-" + strLayerId
                + "\",\"type\":\"index-pattern\"}],\"type\":\"lens\",\"updated_at\":\"2020-12-27T09:57:38.881Z\",\"version\":\"WzQ3Mzk2LDRd\"}";
        SavedObjectService.create( JSONObject.fromObject( strDonutObj ) );
    }

    /**
     * create map visualization
     * 
     * @param visualization
     *            visualisation
     */
    public static void createMapVisualization( String strTitle, String strFieldName, String strIdVisualization, String strIdIndexPattern, String queryFilter )
    {
        String strMapObj = "{\"objects\":[{\"attributes\":{\"description\":\"\",\"layerListJSON\":\"[{\\\"sourceDescriptor\\\":{\\\"type\\\":\\\"EMS_TMS\\\",\\\"isAutoSelect\\\":true},\\\"id\\\":\\\"5f4845a6-1b12-4d48-a640-96bf4b68d805\\\",\\\"label\\\":null,\\\"minZoom\\\":0,\\\"maxZoom\\\":24,\\\"alpha\\\":1,\\\"visible\\\":true,\\\"style\\\":{\\\"type\\\":\\\"TILE\\\"},\\\"type\\\":\\\"VECTOR_TILE\\\"},{\\\"sourceDescriptor\\\":{\\\"geoField\\\":\\\""
                + strFieldName
                + "\\\",\\\"filterByMapBounds\\\":true,\\\"scalingType\\\":\\\"CLUSTERS\\\",\\\"topHitsSize\\\":1,\\\"id\\\":\\\"6cc4541c-73ad-46e0-b331-3a14ba5010f4\\\",\\\"type\\\":\\\"ES_SEARCH\\\",\\\"tooltipProperties\\\":[\\\""
                + strFieldName.replace( "elastic.geopoint", "address" )
                + "\\\"],\\\"sortField\\\":\\\"\\\",\\\"sortOrder\\\":\\\"desc\\\",\\\"indexPatternRefName\\\":\\\"layer_1_source_index_pattern\\\"},\\\"id\\\":\\\"b0506a1c-5963-4d75-ae45-049d48ef45be\\\",\\\"label\\\":\\\"Adresse\\\",\\\"minZoom\\\":0,\\\"maxZoom\\\":24,\\\"alpha\\\":0.75,\\\"visible\\\":false,\\\"style\\\":{\\\"type\\\":\\\"VECTOR\\\",\\\"properties\\\":{\\\"icon\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"value\\\":\\\"marker\\\"}},\\\"fillColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#54B399\\\"}},\\\"lineColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#41937c\\\"}},\\\"lineWidth\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"size\\\":1}},\\\"iconSize\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"size\\\":6}},\\\"iconOrientation\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"orientation\\\":0}},\\\"labelText\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"value\\\":\\\"\\\"}},\\\"labelColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#000000\\\"}},\\\"labelSize\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"size\\\":14}},\\\"labelBorderColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#FFFFFF\\\"}},\\\"symbolizeAs\\\":{\\\"options\\\":{\\\"value\\\":\\\"circle\\\"}},\\\"labelBorderSize\\\":{\\\"options\\\":{\\\"size\\\":\\\"SMALL\\\"}}},\\\"isTimeAware\\\":true},\\\"type\\\":\\\"BLENDED_VECTOR\\\",\\\"joins\\\":[]},{\\\"sourceDescriptor\\\":{\\\"type\\\":\\\"ES_GEO_GRID\\\",\\\"id\\\":\\\"2baa1738-6600-47b2-9c59-0122444fe6eb\\\",\\\"geoField\\\":\\\""
                + strFieldName
                + "\\\",\\\"metrics\\\":[{\\\"type\\\":\\\"count\\\",\\\"label\\\":\\\"Nombre de demandes\\\"},{\\\"type\\\":\\\"terms\\\",\\\"field\\\":\\\""
                + strFieldName.replace( "elastic.geopoint", "address.keyword" )
                + "\\\",\\\"label\\\":\\\"Top Adresse\\\"}],\\\"requestType\\\":\\\"point\\\",\\\"resolution\\\":\\\"COARSE\\\",\\\"indexPatternRefName\\\":\\\"layer_2_source_index_pattern\\\"},\\\"style\\\":{\\\"type\\\":\\\"VECTOR\\\",\\\"properties\\\":{\\\"icon\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"value\\\":\\\"marker\\\"}},\\\"fillColor\\\":{\\\"type\\\":\\\"DYNAMIC\\\",\\\"options\\\":{\\\"color\\\":\\\"Blues\\\",\\\"colorCategory\\\":\\\"palette_0\\\",\\\"field\\\":{\\\"name\\\":\\\"doc_count\\\",\\\"origin\\\":\\\"source\\\"},\\\"fieldMetaOptions\\\":{\\\"isEnabled\\\":true,\\\"sigma\\\":3},\\\"type\\\":\\\"ORDINAL\\\"}},\\\"lineColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#FFF\\\"}},\\\"lineWidth\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"size\\\":0}},\\\"iconSize\\\":{\\\"type\\\":\\\"DYNAMIC\\\",\\\"options\\\":{\\\"minSize\\\":7,\\\"maxSize\\\":32,\\\"field\\\":{\\\"name\\\":\\\"doc_count\\\",\\\"origin\\\":\\\"source\\\"},\\\"fieldMetaOptions\\\":{\\\"isEnabled\\\":true,\\\"sigma\\\":3}}},\\\"iconOrientation\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"orientation\\\":0}},\\\"labelText\\\":{\\\"type\\\":\\\"DYNAMIC\\\",\\\"options\\\":{\\\"field\\\":{\\\"name\\\":\\\"doc_count\\\",\\\"origin\\\":\\\"source\\\"}}},\\\"labelColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#000000\\\"}},\\\"labelSize\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"size\\\":14}},\\\"labelBorderColor\\\":{\\\"type\\\":\\\"STATIC\\\",\\\"options\\\":{\\\"color\\\":\\\"#FFFFFF\\\"}},\\\"symbolizeAs\\\":{\\\"options\\\":{\\\"value\\\":\\\"circle\\\"}},\\\"labelBorderSize\\\":{\\\"options\\\":{\\\"size\\\":\\\"SMALL\\\"}}},\\\"isTimeAware\\\":true},\\\"id\\\":\\\"2f0bad2d-3e25-4ca1-ad97-c246b685ed9b\\\",\\\"label\\\":\\\"Nombre d'adresses\\\",\\\"minZoom\\\":0,\\\"maxZoom\\\":24,\\\"alpha\\\":0.75,\\\"visible\\\":true,\\\"type\\\":\\\"VECTOR\\\",\\\"joins\\\":[]},{\\\"sourceDescriptor\\\":{\\\"type\\\":\\\"ES_GEO_GRID\\\",\\\"id\\\":\\\"15628a81-26e3-44ab-8a67-2066e63d70c8\\\",\\\"geoField\\\":\\\""
                + strFieldName
                + "\\\",\\\"metrics\\\":[{\\\"type\\\":\\\"count\\\",\\\"label\\\":\\\"Nombre de demande\\\"}],\\\"requestType\\\":\\\"heatmap\\\",\\\"resolution\\\":\\\"COARSE\\\",\\\"indexPatternRefName\\\":\\\"layer_3_source_index_pattern\\\"},\\\"id\\\":\\\"6df9c480-2b22-433a-a77e-ec00157b93b1\\\",\\\"label\\\":\\\"Intensité de la demande\\\",\\\"minZoom\\\":0,\\\"maxZoom\\\":24,\\\"alpha\\\":0.75,\\\"visible\\\":false,\\\"style\\\":{\\\"type\\\":\\\"HEATMAP\\\",\\\"colorRampName\\\":\\\"theclassic\\\"},\\\"type\\\":\\\"HEATMAP\\\",\\\"joins\\\":[]}]\",\"mapStateJSON\":\"{\\\"zoom\\\":11.51,\\\"center\\\":{\\\"lon\\\":2.36938,\\\"lat\\\":48.85081},\\\"timeFilters\\\":{\\\"from\\\":\\\"now-3y\\\",\\\"to\\\":\\\"now\\\"},\\\"refreshConfig\\\":{\\\"isPaused\\\":true,\\\"interval\\\":10000},\\\"query\\\":{\\\"query\\\":\\\"documentTypeName.keyword : formResponse\\\",\\\"language\\\":\\\"kuery\\\"},\\\"filters\\\":[],\\\"settings\\\":{\\\"autoFitToDataBounds\\\":false,\\\"initialLocation\\\":\\\"LAST_SAVED_LOCATION\\\",\\\"fixedLocation\\\":{\\\"lat\\\":0,\\\"lon\\\":0,\\\"zoom\\\":2},\\\"browserLocation\\\":{\\\"zoom\\\":2},\\\"maxZoom\\\":24,\\\"minZoom\\\":0,\\\"showSpatialFilters\\\":true,\\\"spatialFiltersAlpa\\\":0.3,\\\"spatialFiltersFillColor\\\":\\\"#DA8B45\\\",\\\"spatialFiltersLineColor\\\":\\\"#DA8B45\\\"}}\",\"title\":\""
                + strTitle + "\",\"uiStateJSON\":\"{\\\"isLayerTOCOpen\\\":true,\\\"openTOCDetails\\\":[]}\"},\"id\":\"" + strIdVisualization
                + "\",\"migrationVersion\":{\"map\":\"7.10.0\"},\"references\":[{\"id\":\"" + strIdIndexPattern
                + "\",\"name\":\"layer_1_source_index_pattern\",\"type\":\"index-pattern\"},{\"id\":\"" + strIdIndexPattern
                + "\",\"name\":\"layer_2_source_index_pattern\",\"type\":\"index-pattern\"},{\"id\":\"" + strIdIndexPattern
                + "\",\"name\":\"layer_3_source_index_pattern\",\"type\":\"index-pattern\"}],\"type\":\"map\",\"updated_at\":\"2021-02-09T10:51:18.667Z\",\"version\":\"WzM2NTQ2Nyw4XQ==\"}],\"version\":\"1\"}";
        SavedObjectService.createFromString( strMapObj );
    }
}