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.web;
35  
36  import fr.paris.lutece.plugins.carto.business.BasemapHome;
37  import fr.paris.lutece.plugins.carto.business.Coordonnee;
38  import fr.paris.lutece.plugins.carto.business.CoordonneeHome;
39  import fr.paris.lutece.plugins.carto.business.DataLayer;
40  import fr.paris.lutece.plugins.carto.business.DataLayerHome;
41  import fr.paris.lutece.plugins.carto.business.DataLayerMapTemplate;
42  import fr.paris.lutece.plugins.carto.business.DataLayerMapTemplateHome;
43  import fr.paris.lutece.plugins.carto.business.DataLayerType;
44  import fr.paris.lutece.plugins.carto.business.DataLayerTypeHome;
45  import fr.paris.lutece.plugins.carto.business.IDataLayerDAO;
46  import fr.paris.lutece.plugins.carto.business.MapTemplate;
47  import fr.paris.lutece.plugins.carto.business.MapTemplateHome;
48  import fr.paris.lutece.plugins.cartography.modules.solr.service.CartographyService;
49  import fr.paris.lutece.plugins.leaflet.business.GeolocItem;
50  import fr.paris.lutece.plugins.leaflet.business.GeolocItemPolygon;
51  import fr.paris.lutece.plugins.leaflet.service.IconService;
52  import fr.paris.lutece.plugins.search.solr.business.SolrFacetedResult;
53  import fr.paris.lutece.plugins.search.solr.business.SolrSearchAppConf;
54  import fr.paris.lutece.plugins.search.solr.business.SolrSearchEngine;
55  import fr.paris.lutece.plugins.search.solr.business.SolrSearchResult;
56  import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexerService;
57  import fr.paris.lutece.plugins.search.solr.indexer.SolrItem;
58  import fr.paris.lutece.plugins.search.solr.service.SolrSearchAppConfService;
59  import fr.paris.lutece.plugins.search.solr.web.SolrIndexerJspBean;
60  import fr.paris.lutece.plugins.workflowcore.business.state.State;
61  import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
62  import fr.paris.lutece.portal.web.xpages.XPage;
63  import fr.paris.lutece.portal.util.mvc.xpage.MVCApplication;
64  import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
65  import fr.paris.lutece.portal.util.mvc.xpage.annotations.Controller;
66  import fr.paris.lutece.util.url.UrlItem;
67  import fr.paris.lutece.portal.service.message.SiteMessageService;
68  import fr.paris.lutece.portal.service.message.SiteMessage;
69  import fr.paris.lutece.portal.service.message.SiteMessageException;
70  import fr.paris.lutece.portal.service.security.SecurityTokenService;
71  import fr.paris.lutece.portal.service.spring.SpringContextService;
72  import fr.paris.lutece.portal.service.admin.AccessDeniedException;
73  import fr.paris.lutece.portal.service.util.AppException;
74  import fr.paris.lutece.portal.service.util.AppLogService;
75  
76  import java.io.IOException;
77  import java.util.ArrayList;
78  import java.util.Arrays;
79  import java.util.HashMap;
80  import java.util.List;
81  import java.util.Map;
82  import java.util.Optional;
83  import java.util.Map.Entry;
84  
85  import javax.servlet.http.HttpServletRequest;
86  
87  /**
88   * This class provides the user interface to manage Coordonnee xpages ( manage, create, modify, remove )
89   */
90  @Controller( xpageName = "coordinate", pageTitleI18nKey = "carto.xpage.coordonnee.pageTitle", pagePathI18nKey = "carto.xpage.coordonnee.pagePathLabel" )
91  public class CoordinateXPage extends MVCApplication
92  {
93      // Templates
94      private static final String TEMPLATE_SHOW_MAP_COORDINATE = "/skin/plugins/carto/show_map_coordinate.html";
95      private static final String TEMPLATE_CREATE_COORDONNEE = "/skin/plugins/carto/create_coordonnee.html";
96      private static final String TEMPLATE_MODIFY_COORDONNEE = "/skin/plugins/carto/modify_coordonnee.html";
97  
98      // Parameters
99      private static final String PARAMETER_ID_COORDONNEE = "id";
100     private static final String PARAMETER_SOLR_GEOJSON = "DataLayer_text";
101     private static final String PARAMETER_ID_MAP = "idMap";
102 
103     // Markers
104     private static final String MARK_COORDONNEE_LIST = "coordonnee_list";
105     private static final String MARK_COORDONNEE = "coordonnee";
106 
107     // Message
108     private static final String MESSAGE_CONFIRM_REMOVE_COORDONNEE = "carto.message.confirmRemoveCoordonnee";
109 
110     // Views
111     private static final String VIEW_MANAGE_COORDONNEES = "manageCoordonnees";
112     private static final String VIEW_CREATE_COORDONNEE = "createCoordonnee";
113     private static final String VIEW_MODIFY_COORDONNEE = "modifyCoordonnee";
114 
115     // Actions
116     private static final String ACTION_CREATE_COORDONNEE = "createCoordonnee";
117     private static final String ACTION_MODIFY_COORDONNEE = "modifyCoordonnee";
118     private static final String ACTION_REMOVE_COORDONNEE = "removeCoordonnee";
119     private static final String ACTION_LOAD_MAP = "loadMap";
120     private static final String ACTION_CONFIRM_REMOVE_COORDONNEE = "confirmRemoveCoordonnee";
121 
122     // Infos
123     private static final String INFO_COORDONNEE_CREATED = "carto.info.coordonnee.created";
124     private static final String INFO_COORDONNEE_UPDATED = "carto.info.coordonnee.updated";
125     private static final String INFO_COORDONNEE_REMOVED = "carto.info.coordonnee.removed";
126 
127     // Errors
128     private static final String ERROR_RESOURCE_NOT_FOUND = "Resource not found";
129 
130     private static final String MARK_POINTS = "points";
131     private static final String MARK_POINTS_GEOJSON = "geojson";
132     private static final String MARK_POINTS_ID = "id";
133     private static final String MARK_POINTS_FIELDCODE = "code";
134     private static final String MARK_POINTS_TYPE = "type";
135     private static final String MARK_DATA_LAYER_TITLE = "data_layer_title";
136     private static final String MARK_DATA_LAYER = "data_layer";
137     private static final String MARK_LAYER_EDITABLE = "data_layer_editable";
138     private static final String MARK_MAP = "mapLoaded";
139     private static final String MARK_LAYER_PROPERTIES = "layer_properties";
140     private static final String MARK_LAYER_TYPE = "layer_type";
141     private static final String MARK_LIST_MAP = "list_map";
142     private static final String MARK_BASEMAP = "basemap";
143 
144     // Session variable to store working values
145     private Coordonnee _coordonnee;
146     private static int _idMap = 0;
147 
148     /**
149      * return the form to manage coordonnees
150      * 
151      * @param request
152      *            The Http request
153      * @return the html code of the list of coordonnees
154      */
155     @View( value = VIEW_MANAGE_COORDONNEES, defaultView = true )
156     public XPage getManageCoordonnees( HttpServletRequest request )
157     {
158         _coordonnee = null;
159         Map<String, Object> model = getModel( );
160         model.put( MARK_LIST_MAP, MapTemplateHome.getMapTemplatesReferenceList( ) );
161         if ( _idMap != 0 )
162         {
163             // Charger map
164             MapTemplate map = MapTemplateHome.findByPrimaryKey( _idMap ).get( );
165             // List<Coordonnee> listCoordonnees = CoordonneeHome.getCoordonneesList( );
166 
167             CartographyService.loadMapAndPoints( map, model );
168         }
169         return getXPage( TEMPLATE_SHOW_MAP_COORDINATE, getLocale( request ), model );
170     }
171 
172     /**
173      * Returns a model with points data from a geoloc search
174      * 
175      * @param listResultsGeoloc
176      *            the result of a search
177      * @return the model
178      */
179     private static List<HashMap<String, Object>> getGeolocModel( List<SolrSearchResult> listResultsGeoloc )
180     {
181         List<HashMap<String, Object>> points = new ArrayList<>( listResultsGeoloc.size( ) );
182         Map<String, String> iconKeysCache = new HashMap<>( );
183 
184         for ( SolrSearchResult result : listResultsGeoloc )
185         {
186             Map<String, Object> dynamicFields = result.getDynamicFields( );
187 
188             for ( Entry<String, Object> entry : dynamicFields.entrySet( ) )
189             {
190                 if ( !entry.getKey( ).endsWith( SolrItem.DYNAMIC_GEOJSON_FIELD_SUFFIX ) )
191                 {
192                     continue;
193                 }
194                 HashMap<String, Object> h = new HashMap<>( );
195                 String strJson = (String) entry.getValue( );
196                 GeolocItem geolocItem = null;
197 
198                 try
199                 {
200                     geolocItem = GeolocItem.fromJSON( strJson );
201                 }
202                 catch( IOException e )
203                 {
204                     AppLogService.error( "SolrSearchApp: error parsing geoloc JSON: " + strJson + ", exception " + e );
205                 }
206 
207                 // if ( geolocItem != null && geolocItem.getTypegeometry( ).equals( GeolocItem.VALUE_GEOMETRY_TYPE ) )
208                 if ( geolocItem != null )
209                 {
210                     String strType = result.getId( ).substring( result.getId( ).lastIndexOf( '_' ) + 1 );
211                     String strIcon;
212 
213                     if ( iconKeysCache.containsKey( geolocItem.getIcon( ) ) )
214                     {
215                         strIcon = iconKeysCache.get( geolocItem.getIcon( ) );
216                     }
217                     else
218                     {
219                         strIcon = IconService.getIcon( strType, geolocItem.getIcon( ) );
220                         iconKeysCache.put( geolocItem.getIcon( ), strIcon );
221                     }
222 
223                     geolocItem.setIcon( strIcon );
224                     h.put( MARK_POINTS_GEOJSON, geolocItem.toJSON( ) );
225                     h.put( MARK_POINTS_ID, result.getId( ).substring( result.getId( ).indexOf( '_' ) + 1, result.getId( ).lastIndexOf( '_' ) ) );
226                     h.put( MARK_POINTS_FIELDCODE, entry.getKey( ).substring( 0, entry.getKey( ).lastIndexOf( '_' ) ) );
227                     h.put( MARK_POINTS_TYPE, strType );
228                     h.put( MARK_LAYER_PROPERTIES, iconKeysCache );
229                     points.add( h );
230                 }
231             }
232         }
233         return points;
234     }
235 
236     /**
237      * Returns a model with points data from a geoloc search
238      * 
239      * @param listResultsGeoloc
240      *            the result of a search
241      * @return the model
242      */
243     private static List<HashMap<String, Object>> getGeolocModel( List<SolrSearchResult> listResultsGeoloc, DataLayer datalayer,
244             DataLayerMapTemplate dataLayerMapTemplate )
245     {
246         List<HashMap<String, Object>> points = new ArrayList<>( listResultsGeoloc.size( ) );
247         Map<String, String> iconKeysCache = new HashMap<>( );
248 
249         for ( SolrSearchResult result : listResultsGeoloc )
250         {
251             Map<String, Object> dynamicFields = result.getDynamicFields( );
252 
253             for ( Entry<String, Object> entry : dynamicFields.entrySet( ) )
254             {
255                 if ( !entry.getKey( ).endsWith( SolrItem.DYNAMIC_GEOJSON_FIELD_SUFFIX ) )
256                 {
257                     continue;
258                 }
259                 HashMap<String, Object> h = new HashMap<>( );
260                 String strJson = (String) entry.getValue( );
261 
262                 // if ( geolocItem != null && geolocItem.getTypegeometry( ).equals( GeolocItem.VALUE_GEOMETRY_TYPE ) )
263                 if ( strJson != null )
264                 {
265                     // geolocItem.setIcon( strIcon );
266                     h.put( MARK_POINTS_GEOJSON, strJson );
267                     h.put( MARK_POINTS_ID, result.getId( ).substring( result.getId( ).indexOf( '_' ) + 1, result.getId( ).lastIndexOf( '_' ) ) );
268                     h.put( MARK_POINTS_FIELDCODE, entry.getKey( ).substring( 0, entry.getKey( ).lastIndexOf( '_' ) ) );
269                     // h.put( MARK_POINTS_TYPE, strType );
270                     h.put( MARK_DATA_LAYER_TITLE, datalayer.getTitle( ) );
271                     // h.put( MARK_DATA_LAYER, datalayer );
272                     h.put( MARK_LAYER_PROPERTIES, dataLayerMapTemplate );
273                     DataLayerType dataLayerType = DataLayerTypeHome.findByPrimaryKey( dataLayerMapTemplate.getLayerType( ) ).get( );
274                     h.put( MARK_LAYER_TYPE, dataLayerType );
275                     points.add( h );
276                 }
277             }
278         }
279         return points;
280     }
281 
282     /**
283      * Returns the form to create a coordonnee
284      *
285      * @param request
286      *            The Http request
287      * @return the html code of the coordonnee form
288      */
289     @View( VIEW_CREATE_COORDONNEE )
290     public XPage getCreateCoordonnee( HttpServletRequest request )
291     {
292         _coordonnee = ( _coordonnee != null ) ? _coordonnee : new Coordonnee( );
293 
294         Map<String, Object> model = getModel( );
295         model.put( MARK_COORDONNEE, _coordonnee );
296         model.put( SecurityTokenService.MARK_TOKEN, SecurityTokenService.getInstance( ).getToken( request, ACTION_CREATE_COORDONNEE ) );
297 
298         return getXPage( TEMPLATE_CREATE_COORDONNEE, getLocale( request ), model );
299     }
300 
301     /**
302      * Process the data capture form of a new coordonnee
303      *
304      * @param request
305      *            The Http Request
306      * @return The Jsp URL of the process result
307      * @throws AccessDeniedException
308      */
309     @Action( ACTION_CREATE_COORDONNEE )
310     public XPage doCreateCoordonnee( HttpServletRequest request ) throws AccessDeniedException
311     {
312         // Data Layer
313         DataLayer datalayer = new DataLayer( );
314         if ( request.getParameter( "iddatalayer" ) != null && !request.getParameter( "iddatalayer" ).isEmpty( ) )
315         {
316             Optional<DataLayer> dlayer = DataLayerHome.findByPrimaryKey( Integer.valueOf( request.getParameter( "iddatalayer" ) ) );
317             if ( dlayer.isPresent( ) )
318             {
319                 datalayer = dlayer.get( );
320             }
321         }
322 
323         // Point
324         if ( request.getParameter( "coordinate_x" ) != null && !request.getParameter( "coordinate_x" ).isEmpty( )
325                 && request.getParameter( "coordinate_y" ) != null && !request.getParameter( "coordinate_y" ).isEmpty( ) )
326         {
327             double x = Double.valueOf( request.getParameter( "coordinate_x" ) );
328             double y = Double.valueOf( request.getParameter( "coordinate_y" ) );
329 
330             String adresse = "";
331 
332             Coordonnee coord = new Coordonnee( );
333             coord.setAdresse( "" );
334             coord.setCoordonneeX( x );
335             coord.setCoordonneeY( y );
336 
337             GeolocItem geolocItem = new GeolocItem( );
338             HashMap<String, Object> properties = new HashMap<>( );
339             properties.put( GeolocItem.PATH_PROPERTIES_ADDRESS, adresse );
340 
341             HashMap<String, Object> geometry = new HashMap<>( );
342             geometry.put( GeolocItem.PATH_GEOMETRY_COORDINATES, Arrays.asList( x, y ) );
343             geometry.put( GeolocItem.PATH_GEOMETRY_TYPE, GeolocItem.VALUE_GEOMETRY_TYPE );
344             geolocItem.setGeometry( geometry );
345             geolocItem.setProperties( properties );
346 
347             coord.setGeoJson( geolocItem.toJSON( ) );
348             coord.setDataLayer( datalayer );
349             CoordonneeHome.create( coord );
350         }
351 
352         // Polygon
353         String coordPolygon = request.getParameter( "coordinate_polygon" );
354         if ( coordPolygon != null && !coordPolygon.isEmpty( ) )
355         {
356             createCoordinate( coordPolygon, GeolocItem.VALUE_GEOMETRY_TYPE_POLYGON, datalayer );
357         }
358 
359         // Polyline
360         String coordPolyline = request.getParameter( "coordinate_polyline" );
361         if ( coordPolyline != null && !coordPolyline.isEmpty( ) )
362         {
363             createCoordinate( coordPolyline, GeolocItem.VALUE_GEOMETRY_TYPE_POLYLINE, datalayer );
364         }
365 
366         SolrIndexerService.processIndexing( true );
367 
368         return redirectView( request, VIEW_MANAGE_COORDONNEES );
369     }
370 
371     private static void createCoordinate( String coordinate, String strTypeGeometry, DataLayer datalayer )
372     {
373         String [ ] lstCoordPolygon = coordinate.split( ";" );
374 
375         GeolocItemPolygon geoPolygon = new GeolocItemPolygon( );
376         List<List<Double>> polygonLonLoat = new ArrayList<>( );
377         List<List<List<Double>>> polygonCoord = new ArrayList<>( );
378         HashMap<String, Object> geometryPolygon = new HashMap<>( );
379 
380         for ( String coordPolygonXY : lstCoordPolygon )
381         {
382             String [ ] coordPolygonXY2 = coordPolygonXY.split( "," );
383             double polygonx = Double.valueOf( coordPolygonXY2 [0] );
384             double polygony = Double.valueOf( coordPolygonXY2 [1] );
385             polygonLonLoat.add( Arrays.asList( polygonx, polygony ) );
386         }
387         // End polygon with first coordinate for polygon
388         if ( strTypeGeometry.equals( GeolocItemPolygon.VALUE_GEOMETRY_TYPE_POLYGON ) )
389         {
390             String [ ] coordPolygonXY2 = lstCoordPolygon [0].split( "," );
391             double polygonx = Double.valueOf( coordPolygonXY2 [0] );
392             double polygony = Double.valueOf( coordPolygonXY2 [1] );
393             polygonLonLoat.add( Arrays.asList( polygonx, polygony ) );
394             polygonCoord.add( polygonLonLoat );
395             geometryPolygon.put( GeolocItem.PATH_GEOMETRY_COORDINATES, polygonCoord );
396         }
397         else
398             if ( strTypeGeometry.equals( GeolocItemPolygon.VALUE_GEOMETRY_TYPE_POLYLINE ) )
399             {
400                 geometryPolygon.put( GeolocItem.PATH_GEOMETRY_COORDINATES, polygonLonLoat );
401             }
402 
403         geoPolygon.setGeometry( geometryPolygon );
404         geoPolygon.setTypegeometry( strTypeGeometry );
405 
406         Coordonnee coord = new Coordonnee( );
407         coord.setAdresse( "" );
408         coord.setCoordonneeX( 0.0 );
409         coord.setCoordonneeY( 0.0 );
410         coord.setGeoJson( geoPolygon.toJSON( ) );
411         coord.setDataLayer( datalayer );
412         CoordonneeHome.create( coord );
413     }
414 
415     /**
416      * Load the map
417      *
418      * @param request
419      *            The Http request
420      * @return the jsp URL to display the form to manage coordonnees
421      */
422     @Action( ACTION_LOAD_MAP )
423     public XPage doLoadMap( HttpServletRequest request )
424     {
425         _idMap = Integer.parseInt( request.getParameter( PARAMETER_ID_MAP ) );
426         // addInfo( INFO_COORDONNEE_REMOVED, getLocale( request ) );
427 
428         return redirectView( request, VIEW_MANAGE_COORDONNEES );
429     }
430 
431     /**
432      * Manages the removal form of a coordonnee whose identifier is in the http request
433      *
434      * @param request
435      *            The Http request
436      * @return the html code to confirm
437      * @throws fr.paris.lutece.portal.service.message.SiteMessageException
438      *             {@link fr.paris.lutece.portal.service.message.SiteMessageException}
439      */
440     @Action( ACTION_CONFIRM_REMOVE_COORDONNEE )
441     public XPage getConfirmRemoveCoordonnee( HttpServletRequest request ) throws SiteMessageException
442     {
443         int nId = Integer.parseInt( request.getParameter( PARAMETER_ID_COORDONNEE ) );
444 
445         UrlItem url = new UrlItem( getActionFullUrl( ACTION_REMOVE_COORDONNEE ) );
446         url.addParameter( PARAMETER_ID_COORDONNEE, nId );
447 
448         SiteMessageService.setMessage( request, MESSAGE_CONFIRM_REMOVE_COORDONNEE, SiteMessage.TYPE_CONFIRMATION, url.getUrl( ) );
449         return null;
450     }
451 
452     /**
453      * Handles the removal form of a coordonnee
454      *
455      * @param request
456      *            The Http request
457      * @return the jsp URL to display the form to manage coordonnees
458      */
459     @Action( ACTION_REMOVE_COORDONNEE )
460     public XPage doRemoveCoordonnee( HttpServletRequest request )
461     {
462         int nId = Integer.parseInt( request.getParameter( PARAMETER_ID_COORDONNEE ) );
463         CoordonneeHome.remove( nId );
464         addInfo( INFO_COORDONNEE_REMOVED, getLocale( request ) );
465 
466         return redirectView( request, VIEW_MANAGE_COORDONNEES );
467     }
468 
469     /**
470      * Returns the form to update info about a coordonnee
471      *
472      * @param request
473      *            The Http request
474      * @return The HTML form to update info
475      */
476     @View( VIEW_MODIFY_COORDONNEE )
477     public XPage getModifyCoordonnee( HttpServletRequest request )
478     {
479         int nId = Integer.parseInt( request.getParameter( PARAMETER_ID_COORDONNEE ) );
480 
481         if ( _coordonnee == null || ( _coordonnee.getId( ) != nId ) )
482         {
483             Optional<Coordonnee> optCoordonnee = CoordonneeHome.findByPrimaryKey( nId );
484             _coordonnee = optCoordonnee.orElseThrow( ( ) -> new AppException( ERROR_RESOURCE_NOT_FOUND ) );
485         }
486 
487         Map<String, Object> model = getModel( );
488         model.put( MARK_COORDONNEE, _coordonnee );
489         model.put( SecurityTokenService.MARK_TOKEN, SecurityTokenService.getInstance( ).getToken( request, ACTION_MODIFY_COORDONNEE ) );
490 
491         return getXPage( TEMPLATE_MODIFY_COORDONNEE, getLocale( request ), model );
492     }
493 
494     /**
495      * Process the change form of a coordonnee
496      *
497      * @param request
498      *            The Http request
499      * @return The Jsp URL of the process result
500      * @throws AccessDeniedException
501      */
502     @Action( ACTION_MODIFY_COORDONNEE )
503     public XPage doModifyCoordonnee( HttpServletRequest request ) throws AccessDeniedException
504     {
505         populate( _coordonnee, request, getLocale( request ) );
506 
507         if ( !SecurityTokenService.getInstance( ).validate( request, ACTION_MODIFY_COORDONNEE ) )
508         {
509             throw new AccessDeniedException( "Invalid security token" );
510         }
511 
512         // Check constraints
513         if ( !validateBean( _coordonnee ) )
514         {
515             return redirect( request, VIEW_MODIFY_COORDONNEE, PARAMETER_ID_COORDONNEE, _coordonnee.getId( ) );
516         }
517 
518         CoordonneeHome.update( _coordonnee );
519         addInfo( INFO_COORDONNEE_UPDATED, getLocale( request ) );
520 
521         return redirectView( request, VIEW_MANAGE_COORDONNEES );
522     }
523 }