View Javadoc
1   /*
2    * Copyright (c) 2002-2023, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.cartography.modules.solr.service;
35  
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.Arrays;
39  import java.util.HashMap;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.Optional;
43  import java.util.regex.Matcher;
44  import java.util.regex.Pattern;
45  
46  import org.apache.commons.lang3.StringUtils;
47  
48  import java.util.Map.Entry;
49  
50  import fr.paris.lutece.plugins.carto.business.BasemapHome;
51  import fr.paris.lutece.plugins.carto.business.DataLayer;
52  import fr.paris.lutece.plugins.carto.business.DataLayerHome;
53  import fr.paris.lutece.plugins.carto.business.DataLayerMapTemplate;
54  import fr.paris.lutece.plugins.carto.business.DataLayerMapTemplateHome;
55  import fr.paris.lutece.plugins.carto.business.DataLayerType;
56  import fr.paris.lutece.plugins.carto.business.DataLayerTypeHome;
57  import fr.paris.lutece.plugins.carto.business.MapTemplate;
58  import fr.paris.lutece.plugins.cartography.modules.solr.provider.CartoSolrMarkerProvider;
59  import fr.paris.lutece.plugins.leaflet.business.GeolocItem;
60  import fr.paris.lutece.plugins.leaflet.business.GeolocItemPolygon;
61  import fr.paris.lutece.plugins.leaflet.service.IconService;
62  import fr.paris.lutece.plugins.search.solr.business.SolrSearchEngine;
63  import fr.paris.lutece.plugins.search.solr.business.SolrSearchResult;
64  import fr.paris.lutece.plugins.search.solr.indexer.SolrItem;
65  import fr.paris.lutece.portal.service.util.AppLogService;
66  import fr.paris.lutece.portal.service.util.AppPropertiesService;
67  
68  public class CartographyService
69  {
70  
71      public static final String MARK_POINTS = "points";
72      public static final String MARK_POINTS_GEOJSON = "geojson";
73      public static final String MARK_POINTS_ID = "id";
74      public static final String MARK_POINTS_FIELDCODE = "code";
75      public static final String MARK_POINTS_TYPE = "type";
76      public static final String MARK_DATA_LAYER_TITLE = "data_layer_title";
77      public static final String MARK_DATA_LAYER_POPUP = "data_layer_popup";
78      public static final String MARK_DATA_LAYER = "data_layer";
79      public static final String MARK_LAYER_EDITABLE = "data_layer_editable";
80      public static final String MARK_MAP = "mapLoaded";
81      public static final String MARK_BASEMAP = "basemap";
82      public static final String MARK_BASEMAP_TITLE = "basemap_title";
83      public static final String MARK_BASEMAP_ATTRIBUTION = "basemap_attribution";
84      public static final String MARK_LAYER_PROPERTIES = "layer_properties";
85      public static final String MARK_LAYER_TYPE = "layer_type";
86      public static final String PARAMETER_SOLR_GEOJSON = "DataLayer_text";
87      public static final String MARK_LIMIT_VERTEX = "limit_vertex";
88  
89      private static final String PROPERTY_LIMIT_VERTEX = "map.limit.vertex";
90      private static final String PROPERTY_LIMIT_RESULT_SOLR = "map.limit.result.solr";
91  
92      /**
93       * Returns a model with points data from a geoloc search
94       * 
95       * @param listResultsGeoloc
96       *            the result of a search
97       * @return the model
98       */
99      public static List<HashMap<String, Object>> getGeolocModel( List<SolrSearchResult> listResultsGeoloc, DataLayer datalayer,
100             DataLayerMapTemplate dataLayerMapTemplate )
101     {
102         List<HashMap<String, Object>> points = new ArrayList<>( listResultsGeoloc.size( ) );
103         Map<String, String> iconKeysCache = new HashMap<>( );
104 
105         for ( SolrSearchResult result : listResultsGeoloc )
106         {
107             Map<String, Object> dynamicFields = result.getDynamicFields( );
108 
109             String uid = result.getId( );
110 
111             for ( Entry<String, Object> entry : dynamicFields.entrySet( ) )
112             {
113 
114                 if ( !entry.getKey( ).endsWith( SolrItem.DYNAMIC_GEOJSON_FIELD_SUFFIX ) )
115                 {
116                     continue;
117                 }
118                 HashMap<String, Object> h = new HashMap<>( );
119                 String strJson = (String) entry.getValue( );
120                 GeolocItem geolocItem = null;
121 
122                 try
123                 {
124                     geolocItem = GeolocItem.fromJSON( strJson );
125                 }
126                 catch( IOException e )
127                 {
128                     AppLogService.error( "SolrSearchApp: error parsing geoloc JSON: " + strJson + ", exception " + e );
129                 }
130 
131                 // if ( geolocItem != null && geolocItem.getTypegeometry( ).equals( GeolocItem.VALUE_GEOMETRY_TYPE ) )
132                 if ( geolocItem != null )
133                 {
134                     String strType = result.getId( ).substring( result.getId( ).lastIndexOf( '_' ) + 1 );
135                     String strIcon;
136 
137                     if ( iconKeysCache.containsKey( geolocItem.getIcon( ) ) )
138                     {
139                         strIcon = iconKeysCache.get( geolocItem.getIcon( ) );
140                     }
141                     else
142                     {
143                         strIcon = IconService.getIcon( strType, geolocItem.getIcon( ) );
144                         iconKeysCache.put( geolocItem.getIcon( ), strIcon );
145                     }
146 
147                     geolocItem.setIcon( strIcon );
148                     h.put( MARK_POINTS_GEOJSON, geolocItem.toJSON( ) );
149                     h.put( MARK_POINTS_ID, result.getId( ).substring( result.getId( ).indexOf( '_' ) + 1, result.getId( ).lastIndexOf( '_' ) ) );
150                     h.put( MARK_POINTS_FIELDCODE, entry.getKey( ).substring( 0, entry.getKey( ).lastIndexOf( '_' ) ) );
151                     h.put( MARK_POINTS_TYPE, strType );
152                     if ( datalayer != null )
153                     {
154                         h.put( MARK_DATA_LAYER_TITLE, datalayer.getTitle( ) );
155                         if ( datalayer.getPopupContent( ) != null && !datalayer.getPopupContent( ).isEmpty( ) )
156                         {
157                             String popupContent = replaceMarker( datalayer.getPopupContent( ), uid, datalayer.getSolrTag( ) );
158                             popupContent = popupContent.replaceAll( "[\\r\\n]+", "" );
159                             h.put( MARK_DATA_LAYER_POPUP, popupContent );
160                         }
161                         else
162                         {
163                             h.put( MARK_DATA_LAYER_POPUP, StringUtils.EMPTY );
164                         }
165                         h.put( MARK_DATA_LAYER, datalayer );
166 
167                     }
168                     // h.put( MARK_DATA_LAYER, datalayer );
169                     if ( dataLayerMapTemplate != null )
170                     {
171                         h.put( MARK_LAYER_PROPERTIES, dataLayerMapTemplate );
172                         DataLayerType dataLayerType = DataLayerTypeHome.findByPrimaryKey( dataLayerMapTemplate.getLayerType( ) ).get( );
173                         h.put( MARK_LAYER_TYPE, dataLayerType );
174                     }
175                     points.add( h );
176                 }
177             }
178         }
179         
180         return points;
181     }
182     
183     public static List<HashMap<String, Object>> getWFSFluxModel( int nIdMap )
184     {
185     	List<HashMap<String, Object>> points = new ArrayList<>( );
186         
187         for ( DataLayer datalayerWFS : DataLayerHome.getDataLayersListWFS( nIdMap ) )
188         {
189         	HashMap<String, Object> h = new HashMap<>( );
190         	
191         	h.put( MARK_DATA_LAYER, datalayerWFS );
192         	h.put( MARK_DATA_LAYER_TITLE, datalayerWFS.getTitle( ) );
193         	
194         	points.add( h );
195         }
196         
197         return points;
198     }
199 
200     // public static String replaceTokens(String text, Map<String, String> replacements)
201     public static String replaceMarker( String text, String uid, String solrTag )
202     {
203         Pattern pattern = Pattern.compile( "\\[(.+?)\\]" );
204         Matcher matcher = pattern.matcher( text );
205         StringBuffer buffer = new StringBuffer( );
206 
207         CartoSolrMarkerProviderdules/solr/provider/CartoSolrMarkerProvider.html#CartoSolrMarkerProvider">CartoSolrMarkerProvider cartoMarker = new CartoSolrMarkerProvider( );
208 
209         while ( matcher.find( ) )
210         {
211             Map<String, String> replacements = cartoMarker.valueMarker( matcher.group( 1 ), solrTag, uid );
212             String replacement = replacements.get( matcher.group( 1 ) );
213             if ( replacement != null )
214             {
215                 // matcher.appendReplacement(buffer, replacement);
216                 // see comment
217                 matcher.appendReplacement( buffer, "" );
218                 buffer.append( replacement );
219             }
220             else
221             {
222                 matcher.appendReplacement( buffer, "" );
223                 buffer.append( " " );
224             }
225         }
226         matcher.appendTail( buffer );
227         return buffer.toString( );
228     }
229 
230     /**
231      * get a geolocitem point from coordinate
232      * 
233      * @param x
234      *            coordinate x
235      * @param y
236      *            coordinate y
237      * @param adresse
238      * @return
239      */
240     public static GeolocItem getGeolocItemPoint( Double x, Double y, String adresse )
241     {
242 
243         GeolocItem geolocItem = new GeolocItem( );
244         HashMap<String, Object> properties = new HashMap<>( );
245         properties.put( GeolocItem.PATH_PROPERTIES_ADDRESS, adresse );
246 
247         HashMap<String, Object> geometry = new HashMap<>( );
248         geometry.put( GeolocItem.PATH_GEOMETRY_COORDINATES, Arrays.asList( x, y ) );
249         geometry.put( GeolocItem.PATH_GEOMETRY_TYPE, GeolocItem.VALUE_GEOMETRY_TYPE );
250         geolocItem.setGeometry( geometry );
251         geolocItem.setProperties( properties );
252 
253         return geolocItem;
254     }
255 
256     /**
257      * get a geolocitem polygon or polyline from coordinates
258      * 
259      * @param coordinate
260      * @param strTypeGeometry
261      *            Polygon or Polyline
262      * @return
263      */
264     public static GeolocItemPolygon getGeolocItemPolygon( String coordinate, String strTypeGeometry )
265     {
266         String [ ] lstCoordPolygon = coordinate.split( ";" );
267 
268         GeolocItemPolygon geoPolygon = new GeolocItemPolygon( );
269         List<List<Double>> polygonLonLoat = new ArrayList<>( );
270 
271         for ( String coordPolygonXY : lstCoordPolygon )
272         {
273             String [ ] coordPolygonXY2 = coordPolygonXY.split( "," );
274             double polygonx = Double.valueOf( coordPolygonXY2 [0] );
275             double polygony = Double.valueOf( coordPolygonXY2 [1] );
276             polygonLonLoat.add( Arrays.asList( polygonx, polygony ) );
277         }
278 
279         HashMap<String, Object> geometryPolygon = new HashMap<>( );
280         geometryPolygon.put( GeolocItem.PATH_GEOMETRY_COORDINATES, polygonLonLoat );
281         geoPolygon.setGeometry( geometryPolygon );
282         geoPolygon.setTypegeometry( strTypeGeometry );
283 
284         return geoPolygon;
285     }
286 
287     /**
288      * load model carto into the map
289      * 
290      * @param map
291      * @param model
292      */
293     public static void loadMapAndPoints( MapTemplate map, Map<String, Object> model )
294     {
295         SolrSearchEngine engine = SolrSearchEngine.getInstance( );
296 
297         List<HashMap<String, Object>> points = new ArrayList<HashMap<String, Object>>( );
298         List<DataLayer> lstDatalayer = DataLayerMapTemplateHome.getDataLayerListByMapTemplateId( map.getId( ) );
299         Optional<DataLayer> dataLayerEditable = DataLayerHome.findDataLayerFromMapId( map.getId( ), true, false, false );
300         int nlimit = AppPropertiesService.getPropertyInt( PROPERTY_LIMIT_RESULT_SOLR, 100 );
301 
302         for ( DataLayer datalayer : lstDatalayer )
303         {
304             List<SolrSearchResult> listResultsGeoloc = engine.getGeolocSearchResults( PARAMETER_SOLR_GEOJSON + ":" + datalayer.getSolrTag( ), null, nlimit );
305             Optional<DataLayerMapTemplate> dataLayerMapTemplate = DataLayerMapTemplateHome.findByIdMapKeyIdDataLayerKey( map.getId( ), datalayer.getId( ) );
306             points.addAll( CartographyService.getGeolocModel( listResultsGeoloc, datalayer, dataLayerMapTemplate.get( ) ) );
307         }
308         points.addAll( CartographyService.getWFSFluxModel( map.getId( ) ) );
309 
310         model.put( CartographyService.MARK_POINTS, points );
311         model.put( CartographyService.MARK_MAP, map );
312         model.put( MARK_BASEMAP, BasemapHome.findByPrimaryKey( Integer.valueOf( map.getMapBackground( ) ) ).get( ).getUrl( ) );
313         model.put( MARK_BASEMAP_TITLE, BasemapHome.findByPrimaryKey( Integer.valueOf( map.getMapBackground( ) ) ).get( ).getTitle( ) );
314         model.put( MARK_BASEMAP_ATTRIBUTION, BasemapHome.findByPrimaryKey( Integer.valueOf( map.getMapBackground( ) ) ).get( ).getAttribution( ) );
315         model.put( MARK_LIMIT_VERTEX, AppPropertiesService.getProperty( PROPERTY_LIMIT_VERTEX ) );
316         if ( dataLayerEditable.isPresent( ) )
317         {
318             model.put( CartographyService.MARK_LAYER_EDITABLE, dataLayerEditable.get( ) );
319         }
320     }
321 
322 }