View Javadoc
1   /*
2    * Copyright (c) 2002-2022, 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.portal.service.dashboard.admin;
35  
36  import java.util.ArrayList;
37  import java.util.Collections;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Map;
41  
42  import javax.servlet.http.HttpServletRequest;
43  
44  import org.apache.commons.collections.CollectionUtils;
45  
46  import fr.paris.lutece.portal.business.dashboard.AdminDashboardFactory;
47  import fr.paris.lutece.portal.business.dashboard.AdminDashboardFilter;
48  import fr.paris.lutece.portal.business.dashboard.AdminDashboardHome;
49  import fr.paris.lutece.portal.business.user.AdminUser;
50  import fr.paris.lutece.portal.service.dashboard.DashboardComponentEntry;
51  import fr.paris.lutece.portal.service.plugin.Plugin;
52  import fr.paris.lutece.portal.service.util.AppLogService;
53  import fr.paris.lutece.portal.service.util.AppPropertiesService;
54  
55  /**
56   *
57   * AdminDashboardService
58   *
59   */
60  public final class AdminDashboardService
61  {
62      /**
63       * admindashboard.columnCount
64       */
65      private static final String PROPERTY_COLUMN_COUNT = "admindashboard.columnCount";
66      private static final String ALL = "ALL";
67      private static final int CONSTANTE_FIRST_ORDER = 1;
68      private static final int CONSTANTE_DEFAULT_COLUMN_COUNT = 2;
69      private static AdminDashboardServicerd/admin/AdminDashboardService.html#AdminDashboardService">AdminDashboardService _singleton = new AdminDashboardService( );
70  
71      /**
72       * Private Constructor
73       */
74      private AdminDashboardService( )
75      {
76          // nothing
77      }
78  
79      /**
80       * Return the unique instance
81       * 
82       * @return The instance
83       */
84      public static AdminDashboardService getInstance( )
85      {
86          return _singleton;
87      }
88  
89      /**
90       * Returns the column count, with {@link AdminDashboardService#PROPERTY_COLUMN_COUNT}. Default is
91       * {@link AdminDashboardService#CONSTANTE_DEFAULT_COLUMN_COUNT}
92       * 
93       * @return the column count
94       */
95      public int getColumnCount( )
96      {
97          return AppPropertiesService.getPropertyInt( PROPERTY_COLUMN_COUNT, CONSTANTE_DEFAULT_COLUMN_COUNT );
98      }
99  
100     /**
101      * All known dashboards as declared in SpringContext
102      * 
103      * @return dashboards list
104      */
105     public List<IAdminDashboardComponent> getAllAdminDashboardComponents( )
106     {
107         return AdminDashboardFactory.getAllAdminDashboardComponents( );
108     }
109 
110     /**
111      *
112      * @param nColumn
113      *            the column id
114      * @return all dashboards for this column
115      */
116     public List<IAdminDashboardComponent> getAdminDashboardComponents( int nColumn )
117     {
118         AdminDashboardFilterashboard/AdminDashboardFilter.html#AdminDashboardFilter">AdminDashboardFilter filter = new AdminDashboardFilter( );
119         filter.setFilterColumn( nColumn );
120 
121         return AdminDashboardHome.findByFilter( filter );
122     }
123 
124     /**
125      * Register a Dashboard Component
126      * 
127      * @param entry
128      *            The DashboardComponent entry defined in the plugin's XML file
129      * @param plugin
130      *            The plugin
131      */
132     public void registerDashboardComponent( DashboardComponentEntry entry, Plugin plugin )
133     {
134         try
135         {
136             IAdminDashboardComponent/../../fr/paris/lutece/portal/service/dashboard/admin/IAdminDashboardComponent.html#IAdminDashboardComponent">IAdminDashboardComponent dc = (IAdminDashboardComponent) Class.forName( entry.getComponentClass( ) ).newInstance( );
137 
138             dc.setName( entry.getName( ) );
139             dc.setPlugin( plugin );
140 
141             boolean bRegistered = AdminDashboardFactory.registerDashboardComponent( dc );
142 
143             if ( bRegistered )
144             {
145                 AppLogService.info( "New Admin Dashboard Component registered : {}", entry.getName( ) );
146             }
147             else
148             {
149                 AppLogService.error( " Admin Dashboard Component not registered : {} : {}", entry.getName( ), entry.getComponentClass( ) );
150             }
151         }
152         catch( ClassNotFoundException | InstantiationException | IllegalAccessException e )
153         {
154             AppLogService.error( "Error registering an Admin DashboardComponent : {}", e.getMessage( ), e );
155         }
156     }
157 
158     /**
159      * Moves the dashboard.
160      * 
161      * @param dashboard
162      *            to move, with new values
163      * @param nOldColumn
164      *            previous column id
165      * @param nOldOrder
166      *            previous order
167      * @param bCreate
168      *            <code>true</code> if this is a new dashboard, <code>false</code> otherwise.
169      */
170     public void doMoveDashboard( IAdminDashboardComponent dashboard, int nOldColumn, int nOldOrder, boolean bCreate )
171     {
172         int nColumn = dashboard.getZone( );
173         int nOrder = dashboard.getOrder( );
174 
175         // find the dashboard already with this order and column
176         AdminDashboardFilterashboard/AdminDashboardFilter.html#AdminDashboardFilter">AdminDashboardFilter filter = new AdminDashboardFilter( );
177         filter.setFilterColumn( nColumn );
178 
179         List<IAdminDashboardComponent> listColumnDashboards = AdminDashboardHome.findByFilter( filter );
180 
181         if ( CollectionUtils.isNotEmpty( listColumnDashboards ) )
182         {
183             if ( AppLogService.isDebugEnabled( ) )
184             {
185                 AppLogService.debug( "Reordering admin dashboard column " + dashboard.getZone( ) );
186             }
187 
188             // sort by order
189             Collections.sort( listColumnDashboards );
190 
191             int nMaxOrder = listColumnDashboards.get( listColumnDashboards.size( ) - 1 ).getOrder( );
192 
193             if ( ( nOldColumn == 0 ) || ( nOldColumn != nColumn ) )
194             {
195                 // was not in this column before, put to the end
196                 dashboard.setOrder( nMaxOrder + 1 );
197             }
198             else
199             {
200                 updateDashboardComponents( dashboard, listColumnDashboards, nOldOrder );
201 
202                 // dashboard are singletons, values are modified by getting it from database
203                 dashboard.setOrder( nOrder );
204                 dashboard.setZone( nColumn );
205             }
206         }
207         else
208         {
209             dashboard.setOrder( 1 );
210         }
211 
212         if ( bCreate )
213         {
214             // create dashboard
215             AdminDashboardHome.create( dashboard );
216         }
217         else
218         {
219             // update dashboard
220             AdminDashboardHome.update( dashboard );
221         }
222     }
223 
224     private void updateDashboardComponents( IAdminDashboardComponent dashboard, List<IAdminDashboardComponent> listColumnDashboards, int nOldOrder )
225     {
226         int nOrder = dashboard.getOrder( );
227         if ( nOrder < nOldOrder )
228         {
229             for ( IAdminDashboardComponent dc : listColumnDashboards )
230             {
231                 int nCurrentOrder = dc.getOrder( );
232 
233                 if ( !dc.equals( dashboard ) && ( nCurrentOrder >= nOrder ) && ( nCurrentOrder < nOldOrder ) )
234                 {
235                     dc.setOrder( nCurrentOrder + 1 );
236                     AdminDashboardHome.update( dc );
237                 }
238             }
239         }
240         else
241             if ( nOrder > nOldOrder )
242             {
243                 for ( IAdminDashboardComponent dc : listColumnDashboards )
244                 {
245                     int nCurrentOrder = dc.getOrder( );
246 
247                     if ( !dc.equals( dashboard ) && ( nCurrentOrder <= nOrder ) && ( nCurrentOrder > nOldOrder ) )
248                     {
249                         dc.setOrder( nCurrentOrder - 1 );
250                         AdminDashboardHome.update( dc );
251                     }
252                 }
253             }
254     }
255 
256     /**
257      * Returns all dashboards with no column/order set
258      * 
259      * @return all dashboards with no column/order set
260      */
261     public List<IAdminDashboardComponent> getNotSetDashboards( )
262     {
263         List<IAdminDashboardComponent> listDashboards = AdminDashboardHome.findAll( );
264         List<IAdminDashboardComponent> listSpringDashboards = getAllAdminDashboardComponents( );
265 
266         List<IAdminDashboardComponent> listUnsetDashboards = new ArrayList<>( );
267 
268         for ( IAdminDashboardComponent dashboard : listSpringDashboards )
269         {
270             if ( !listDashboards.contains( dashboard ) )
271             {
272                 listUnsetDashboards.add( dashboard );
273             }
274         }
275 
276         return listUnsetDashboards;
277     }
278 
279     /**
280      * Finds all dashboard with column and order set.
281      * 
282      * @return a map where key is the column id, and value is the column's dashboard list.
283      */
284     public Map<String, List<IAdminDashboardComponent>> getAllSetDashboards( )
285     {
286         Map<String, List<IAdminDashboardComponent>> mapDashboardComponents = new HashMap<>( );
287 
288         List<IAdminDashboardComponent> listDashboards = AdminDashboardHome.findAll( );
289 
290         for ( IAdminDashboardComponent dashboard : listDashboards )
291         {
292             int nColumn = dashboard.getZone( );
293 
294             String strColumn = Integer.toString( nColumn );
295 
296             // find this column list
297             List<IAdminDashboardComponent> listDashboardsColumn = mapDashboardComponents.computeIfAbsent( strColumn, s -> new ArrayList<>( ) );
298 
299             // add dashboard to the list
300             listDashboardsColumn.add( dashboard );
301         }
302 
303         return mapDashboardComponents;
304     }
305 
306     /**
307      * Gets Data from all components of the zone
308      * 
309      * @param user
310      *            The user
311      * @param nColumn
312      *            The dasboard column
313      * @param request
314      *            HttpServletRequest
315      * @return Data of all components of the zone
316      */
317     public String getDashboardData( AdminUser user, int nColumn, HttpServletRequest request )
318     {
319         StringBuilder sbDashboardData = new StringBuilder( );
320 
321         for ( IAdminDashboardComponent dc : getAdminDashboardComponents( nColumn ) )
322         {
323             boolean bRight = ( dc.getRight( ) == null ) || user.checkRight( dc.getRight( ) ) || dc.getRight( ).equalsIgnoreCase( ALL );
324 
325             if ( dc.isEnabled( ) && bRight )
326             {
327                 sbDashboardData.append( dc.getDashboardData( user, request ) );
328             }
329         }
330 
331         return sbDashboardData.toString( );
332     }
333 
334     /**
335      * Reorders column's dashboard
336      * 
337      * @param nColumn
338      *            the column to reorder
339      */
340     public void doReorderColumn( int nColumn )
341     {
342         int nOrder = CONSTANTE_FIRST_ORDER;
343 
344         for ( IAdminDashboardComponent dc : getAdminDashboardComponents( nColumn ) )
345         {
346             dc.setOrder( nOrder++ );
347             AdminDashboardHome.update( dc );
348         }
349     }
350 
351     /**
352      * Builds the map to with column id as key, and <code>true</code> as value if column is well ordered, <code>false</code> otherwise.
353      * 
354      * @return the map
355      */
356     public Map<String, Boolean> getOrderedColumnsStatus( )
357     {
358         Map<String, Boolean> mapOrderedStatus = new HashMap<>( );
359         List<Integer> listColumns = AdminDashboardHome.findColumns( );
360 
361         for ( Integer nIdColumn : listColumns )
362         {
363             mapOrderedStatus.put( nIdColumn.toString( ), isWellOrdered( nIdColumn ) );
364         }
365 
366         return mapOrderedStatus;
367     }
368 
369     /**
370      * Determines if the column is well ordered
371      * 
372      * @param nColumn
373      *            the column id
374      * @return true if well ordered, <code>false</code> otherwise.
375      */
376     private boolean isWellOrdered( int nColumn )
377     {
378         int nOrder = CONSTANTE_FIRST_ORDER;
379 
380         for ( IAdminDashboardComponent dc : getAdminDashboardComponents( nColumn ) )
381         {
382             if ( nOrder != dc.getOrder( ) )
383             {
384                 return false;
385             }
386 
387             nOrder++;
388         }
389 
390         return true;
391     }
392 }