View Javadoc
1   /*
2    * Copyright (c) 2002-2013, Mairie de 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.directory.modules.gismap.business;
35  
36  import fr.paris.lutece.plugins.directory.business.EntryTypeGeolocation;
37  import fr.paris.lutece.plugins.directory.business.Field;
38  import fr.paris.lutece.plugins.directory.business.FieldHome;
39  import fr.paris.lutece.plugins.directory.business.IEntry;
40  import fr.paris.lutece.plugins.directory.business.Record;
41  import fr.paris.lutece.plugins.directory.business.RecordField;
42  import fr.paris.lutece.plugins.directory.business.RecordFieldFilter;
43  import fr.paris.lutece.plugins.directory.business.RecordFieldHome;
44  import fr.paris.lutece.plugins.directory.business.RecordHome;
45  import fr.paris.lutece.plugins.directory.utils.DirectoryUtils;
46  import fr.paris.lutece.portal.service.plugin.Plugin;
47  import fr.paris.lutece.portal.service.util.AppLogService;
48  import fr.paris.lutece.portal.service.util.AppPropertiesService;
49  
50  import org.apache.commons.lang.BooleanUtils;
51  import org.apache.commons.lang.StringUtils;
52  
53  import net.sf.json.JSONArray;
54  import net.sf.json.JSONException;
55  import net.sf.json.JSONObject;
56  
57  import java.util.ArrayList;
58  import java.util.List;
59  
60  
61  public class RecordsResource
62  {
63  
64  	private static final String GISMAP_VIEW = "gismap.view.";
65  	private static final String PARAMETER = ".parameter.";
66  	private static final String POPUPSHOWLINK = "Popup_ShowLink";
67  	private static final String POPUP = "Popup";
68  	private static final String RMMSHOWCENTROID = "RenderMapManagement.ShowCentroid";
69  	private static final String URL_DIRECTORY_RECORD_DETAIL = "jsp/admin/plugins/directory/DoVisualisationRecord.jsp?";
70  	private static final String PARAMETER_DIRECTORY_RECORD_ID = "id_directory_record=";
71  	private static final String PARAMETER_DIRECTORY_ID = "id_directory=";
72  	private static final String KEY_GEOMETRY = "geometry";
73      
74      
75      protected static final Plugin _directoryPlugin = DirectoryUtils.getPlugin( );
76      
77      
78      private static boolean inProperties( String[] properties, String strProperty )
79      {
80          boolean find = false;
81  
82          for ( int i = 0; !find && ( i < properties.length ); i++ )
83          {
84              find = properties[i].compareTo( "'" + strProperty + "'" ) == 0;
85          }
86  
87          return find;
88      }
89  
90  
91      public static String getLink( Record record )
92      {
93      	String strLink = StringUtils.EMPTY;
94      	Integer idDirectoryRecord = record.getIdRecord(  );
95      	Integer idDirectory = record.getDirectory(  ).getIdDirectory(  );
96      	if ( idDirectoryRecord != null && idDirectory != null)
97      	{
98      		strLink = URL_DIRECTORY_RECORD_DETAIL + PARAMETER_DIRECTORY_RECORD_ID + idDirectoryRecord + "&" + PARAMETER_DIRECTORY_ID + idDirectory;
99      	}
100     	return strLink;
101     }
102 
103  
104     public static String getBestProperties( String strProperties ) // ['nom', 'prenom', 'link']
105     {
106         String strPropertiesReturn = strProperties.replace( "[", "" ).replace( "]", "" );
107 
108         return strPropertiesReturn;
109     }
110 
111     
112     
113 	/** Top-level method preparing the input parameters for building the GeoJSON webservice response. 
114      * 
115      * @param query The object containing query parameters
116      * 
117      * @return
118      */
119     public static String treatListRecordWS( DirectoryGismapSourceQuery query)
120     {
121 
122     	List<Record> listRecord = null;    	
123     	Integer nIdEntryGeolocation = query.getIdGeolocationEntry( );
124     	Integer nIdDirectory = query.getIdDirectory( );
125     	String strIdRecordTab = query.getListIdRecord( );
126     	int nGeoJsonIndex = query.getGeoJsonIndex( );
127     	String strGeoJsonIndex = (nGeoJsonIndex == 0) ? "1" : String.valueOf( nGeoJsonIndex );
128     	String strView = query.getView( );
129     	
130     	 if ( StringUtils.isNotEmpty( strIdRecordTab ) )
131     			 {
132     		 listRecord = getRecordListFromStringParam( strIdRecordTab );
133     			 }
134     	 else
135     	 {
136     		if ( nIdDirectory != null )
137     		{
138     			listRecord = getRecordListFromDirectoryId( nIdDirectory );
139     		}
140     	 }
141     	
142     	return treatListRecordWS( nIdEntryGeolocation, listRecord, strGeoJsonIndex, strView);
143     }
144     
145     
146 	/** Utility method to retrieve the full Record list from a comma-separated String
147 	 * 
148 	 * @param strIdRecordTab The comma-separated list of Record identifiers 
149 	 * 
150 	 * @return List of Records
151 	 */
152     private static List<Record> getRecordListFromStringParam(String strIdRecordTab)
153     {
154     	List<Record> listRecord = new ArrayList<Record>( );
155     	String[] idRecordTab = strIdRecordTab.split(",");
156     	
157     	for ( int i = 0; i < idRecordTab.length; i++ )
158         {
159         Integer nIdRecord = Integer.parseInt( idRecordTab[i] );
160         Record record = RecordHome.findByPrimaryKey( nIdRecord, _directoryPlugin );
161         listRecord.add( record );
162         }
163 
164 		return listRecord;
165 	}
166 
167 
168 	/** Utility method to retrieve the full Record list of a given directory
169 	 * 
170 	 * @param nIdDirectory The directory identifier 
171 	 * 
172 	 * @return List of Records
173 	 */
174 	private static List<Record> getRecordListFromDirectoryId(Integer nIdDirectory)
175 	{
176 		List<Record> listRecord = null;
177 		RecordFieldFilter filter = new RecordFieldFilter( );
178 		filter.setIdDirectory(nIdDirectory);
179 		
180 		listRecord = RecordHome.getListRecord(filter, _directoryPlugin);
181 		
182 		return listRecord;
183 	}
184 
185 
186 	/** Build the GeoJSON webservice response from a list of Record identifiers, a geolocation Entry identifier,
187 	 * a Gismap View identifier and a Geojson source index.
188      * See GEOJSON specification: https://tools.ietf.org/html/rfc7946
189      * 
190      * @param listRecords The list of Record identifiers
191      * 
192      * @param nIdEntryGeolocation The Geolocation Entry identifier
193      * 
194      * @param strGeoJsonIndex The GeoJson source index within gismap view
195      * 
196      * @param strView The Gismap view identifier
197      * 
198      * @return The geoJSON response as a String
199      */
200     public static String treatListRecordWS( Integer nIdEntryGeolocation, List<Record> listRecords, String strGeoJsonIndex, String strView)
201     {  	
202         boolean bRMMSHOWCENTROIDProperty;
203         boolean bPopupShowLinkProperty;
204     	String strPopupProperty;
205     	
206     	strGeoJsonIndex = StringUtils.isEmpty( strGeoJsonIndex ) ? "1" : strGeoJsonIndex;
207     	
208         if ( listRecords != null && nIdEntryGeolocation != null)
209         {
210         	
211 	        if (StringUtils.isEmpty( strView ) )
212 	        {
213 	        	// If view number is not provided
214 	        	// let's retrieve it from geolocation entry ( viewNumberGes field) 
215 	        	strView = getViewNumber(nIdEntryGeolocation);
216 	        }
217         	    	
218 	        bRMMSHOWCENTROIDProperty = getViewPropertyAsBoolean( RMMSHOWCENTROID , strView );    	
219 	        bPopupShowLinkProperty = getViewPropertyAsBoolean( POPUPSHOWLINK , strView);
220 	        strPopupProperty = getPopupProperty(strView, strGeoJsonIndex);
221 	
222 	        String[] strPopupPropertyArray = strPopupProperty.split( "," );
223 	        String[] strProperties = null;
224 	
225 	        if ( strPopupPropertyArray.length > 1 )
226 	        {
227 	            strProperties = getBestProperties( strPopupPropertyArray[1] ).split( ";" );
228 	        }
229 	        
230 	        JSONObject collection = new JSONObject(  );
231 	        collection.accumulate( "type", "FeatureCollection" );
232 	
233 	        JSONArray array = new JSONArray(  );
234 
235 
236             for ( Record record : listRecords )
237             {
238                 String strRecordFieldGeometry = "";
239                 String strRecordFieldX = "";
240                 String strRecordFieldY = "";
241                 JSONObject properties = new JSONObject(  );
242             	
243 
244                 Integer nIdRecord = record.getIdRecord( );
245                 
246                 RecordFieldFilter rfFilter = new RecordFieldFilter( );
247                 rfFilter.setIdRecord( nIdRecord ); 
248                 List<RecordField> listRecordFields = RecordFieldHome.getRecordFieldList(rfFilter, _directoryPlugin);
249                 
250                 for (RecordField recordField : listRecordFields )
251                 {
252                 	 if ( recordField != null )
253                      {
254                 		 
255                          Field field = recordField.getField(  );
256 
257                          if ( field != null )
258                 		 	{
259 	                    	 	if ( field.getTitle(  ).compareTo( EntryTypeGeolocation.CONSTANT_GEOMETRY ) == 0 ) 
260 			                         {
261 			                             strRecordFieldGeometry = recordField.getValue(  );
262 			                         }
263 	                    	 	if ( field.getTitle(  ).compareTo( EntryTypeGeolocation.CONSTANT_X ) == 0 )
264 			                         {
265 			                             strRecordFieldX = recordField.getValue(  );
266 			                         }
267 	                    	 	if ( field.getTitle(  ).compareTo( EntryTypeGeolocation.CONSTANT_Y ) == 0 )
268 			                         {
269 			                             strRecordFieldY = recordField.getValue(  );
270 			                         }
271 	                         
272                     		 }
273                          IEntry entry = recordField.getEntry(  );
274 
275                          if ( inProperties( strProperties, entry.getTitle(  ) ) )
276                          {
277                              properties.accumulate( entry.getTitle(  ), recordField.getValue(  ) );
278                          }
279                      }
280                 }
281 
282                 JSONObject jsonElement = new JSONObject(  );
283                 jsonElement.accumulate( "type", "Feature" );
284                 jsonElement.accumulate( "id", nIdRecord );
285               
286                 if ( bPopupShowLinkProperty )
287                     {
288                         properties.accumulate( "link", getLink( record ) );
289                     }
290     
291                 properties = (properties.size( )== 0 ) ? null : properties;
292                 jsonElement.accumulate( "properties",properties );
293 
294 
295                 jsonElement.accumulate( "geometry", getGeometry( bRMMSHOWCENTROIDProperty, strRecordFieldGeometry, strRecordFieldX, strRecordFieldY ) );
296 
297                 array.add( jsonElement );
298               }
299 
300 	        if ( array.size(  ) > 0 )
301 	        {
302 	            collection.accumulate( "features", array );
303 	        }
304 	        
305 	        return  collection.toString(  );
306         }
307         else
308         {
309         	return StringUtils.EMPTY;
310         }
311     }
312 
313 
314 	private static String getViewNumber(Integer nIdEntryGeolocation)
315 	{
316 		
317 		String strViewNumberValue = StringUtils.EMPTY;
318 		if ( nIdEntryGeolocation != null )
319         {
320             List<Field> fieldList = FieldHome.getFieldListByIdEntry( nIdEntryGeolocation,
321                     _directoryPlugin );
322             for ( Field field : fieldList )
323             {
324                 if ( ( field != null ) && ( field.getTitle(  ) != null ) &&
325                         ( field.getTitle(  ).compareTo( EntryTypeGeolocation.CONSTANT_VIEW_NUMBER_GES ) == 0 ) )
326                 {
327                     strViewNumberValue = field.getValue(  );
328                     break;
329                 }
330             }
331         }
332 		return strViewNumberValue;
333 	}
334 
335     
336 	/** Retrieve the popup1 property value from the provided gismap view number
337 	 * 
338 	 * @param strViewNumberValue
339 	 */
340 	private static String getPopupProperty(String strViewNumberValue, String strGeoJsonIndex) {
341 		String strPopup1Property = AppPropertiesService.getProperty( GISMAP_VIEW + strViewNumberValue + PARAMETER + POPUP+ strGeoJsonIndex );
342 
343         if ( strPopup1Property == null )
344         {
345             strPopup1Property = "";
346             AppLogService.info( "Could not found the " + GISMAP_VIEW + strViewNumberValue + PARAMETER + POPUP+ strGeoJsonIndex +
347                 " property in the property file. Set to empty string" );
348         }
349         return strPopup1Property;
350 	}
351 
352 	/** Retrieve a gismap view property as a boolean value
353 	 * 
354 	 * @param strViewNumberValue
355 	 */
356 	private static boolean getViewPropertyAsBoolean(String strPropertyName, String strViewNumberValue ) {
357 		String strPropertyValue = AppPropertiesService.getProperty( GISMAP_VIEW + strViewNumberValue + PARAMETER +
358 				strPropertyName );
359 
360         if ( StringUtils.isEmpty( strPropertyValue ) )
361         {
362         	strPropertyValue = Boolean.FALSE.toString(  );
363             AppLogService.info( "Could not found the " + GISMAP_VIEW + strViewNumberValue + PARAMETER + strPropertyValue +
364                 " property in the property file. Set to " + Boolean.FALSE.toString(  ) );
365         }
366         return BooleanUtils.toBoolean( strPropertyValue );
367 	}
368 	
369 	/** Retrieve the popupShowLink property value from the provided gismap view number
370 	 * 
371 	 * @param strViewNumberValue
372 	 */
373 	private static String getPopupShowLinkProperty(String strViewNumberValue) {
374 		String strPopupShowLinkProperty = AppPropertiesService.getProperty( GISMAP_VIEW + strViewNumberValue + PARAMETER +
375                 POPUPSHOWLINK );
376 
377         if ( strPopupShowLinkProperty == null )
378         {
379             strPopupShowLinkProperty = Boolean.FALSE.toString(  );
380             AppLogService.info( "Could not found the " + GISMAP_VIEW + strViewNumberValue + PARAMETER + POPUPSHOWLINK +
381                 " property in the property file. Set to " + Boolean.FALSE.toString(  ) );
382         }
383         return strPopupShowLinkProperty;
384 	}
385 
386 	/** Retrieve the ShowCentroid property value from the provided gismap view number
387 	 * 
388 	 * @param strViewNumberValue
389 	 */
390 	private static String getShowCentroidProperty(String strViewNumberValue) {
391 		String strRMMSHOWCENTROIDProperty = AppPropertiesService.getProperty( GISMAP_VIEW + strViewNumberValue +
392                 PARAMETER + RMMSHOWCENTROID );
393     	
394     	 if ( strRMMSHOWCENTROIDProperty == null )
395          {
396     		 strRMMSHOWCENTROIDProperty = Boolean.FALSE.toString(  );
397              AppLogService.info( "Could not found the " + GISMAP_VIEW + strViewNumberValue + PARAMETER + RMMSHOWCENTROID +
398                  " property in the property file. Set to " + Boolean.FALSE.toString(  ) );
399          }
400     	 return strRMMSHOWCENTROIDProperty;
401 	}
402 
403     
404 	/** Build the geometry Geojson node for a feature
405 	 * 
406 	 * @param strRecordFieldGeometry
407 	 * @param strRecordFieldX
408 	 * @param strRecordFieldY
409 	 * 
410 	 * @return the geometry node as a string
411 	 */
412 	private static String getGeometry(boolean bRMMSHOWCENTROIDProperty, String strRecordFieldGeometry, String strRecordFieldX, String strRecordFieldY) {
413 		
414 		String strGeometry = null;
415     	try {
416 	        if ( bRMMSHOWCENTROIDProperty )
417 	        {
418 	            JSONObject jsonCoordinates = new JSONObject(  );
419 	            if ( !strRecordFieldX.isEmpty(  ) && !strRecordFieldY.isEmpty(  ) )
420 	            {
421 	                jsonCoordinates.accumulate( "type", "Point" );
422 	                jsonCoordinates.accumulate( "coordinates", "[" + strRecordFieldX + "," + strRecordFieldY + "]" );
423 	            }
424 	        	
425 	            strGeometry = jsonCoordinates.toString(  ) ;
426 	        }
427 	        else
428 	        {
429 	
430 	        	JSONObject jsonGeometry = JSONObject.fromObject( strRecordFieldGeometry );
431 	        	if (jsonGeometry.containsKey(KEY_GEOMETRY))
432 	        	{
433 	        		strGeometry = jsonGeometry.get(KEY_GEOMETRY).toString( );
434 	        	}
435 	
436 	        }
437     	}
438     	catch ( JSONException e)
439     	{
440     		AppLogService.error("Could not parse the json Geometry for feature "+strRecordFieldGeometry, e);
441     	}
442 
443 		return strGeometry;
444 	}
445 
446     
447 }