DashboardService.java

  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;

  35. import fr.paris.lutece.portal.business.dashboard.DashboardFactory;
  36. import fr.paris.lutece.portal.business.dashboard.DashboardFilter;
  37. import fr.paris.lutece.portal.business.dashboard.DashboardHome;
  38. import fr.paris.lutece.portal.business.user.AdminUser;
  39. import fr.paris.lutece.portal.service.plugin.Plugin;
  40. import fr.paris.lutece.portal.service.spring.SpringContextService;
  41. import fr.paris.lutece.portal.service.util.AppLogService;
  42. import fr.paris.lutece.portal.service.util.AppPropertiesService;
  43. import fr.paris.lutece.util.ReferenceList;
  44. import fr.paris.lutece.util.sort.AttributeComparator;

  45. import java.util.ArrayList;
  46. import java.util.Collections;
  47. import java.util.HashMap;
  48. import java.util.List;
  49. import java.util.Map;

  50. import javax.servlet.http.HttpServletRequest;

  51. import org.apache.commons.collections.CollectionUtils;

  52. /**
  53.  * Dashboard Service
  54.  */
  55. public final class DashboardService
  56. {
  57.     // Properties
  58.     private static final String PROPERTY_COLUMN_COUNT = "dashboard.columnCount";

  59.     // Constants
  60.     private static final String ALL = "ALL";
  61.     private static final String EMPTY_STRING = "";
  62.     private static final String ORDER = "order";
  63.     private static final int CONSTANTE_FIRST_ORDER = 1;
  64.     private static final int CONSTANTE_DEFAULT_COLUMN_COUNT = 3;
  65.     private static DashboardService _singleton = new DashboardService( );

  66.     /**
  67.      * Private Constructor
  68.      */
  69.     private DashboardService( )
  70.     {
  71.     }

  72.     /**
  73.      * Return the unique instance
  74.      *
  75.      * @return The instance
  76.      */
  77.     public static DashboardService getInstance( )
  78.     {
  79.         return _singleton;
  80.     }

  81.     /**
  82.      * Returns the column count, with {@link DashboardService#PROPERTY_COLUMN_COUNT}. Default is {@link DashboardService#CONSTANTE_DEFAULT_COLUMN_COUNT}
  83.      *
  84.      * @return the column count
  85.      */
  86.     public int getColumnCount( )
  87.     {
  88.         return AppPropertiesService.getPropertyInt( PROPERTY_COLUMN_COUNT, CONSTANTE_DEFAULT_COLUMN_COUNT );
  89.     }

  90.     /**
  91.      * All known dashboards as declared in SpringContext
  92.      *
  93.      * @return dashboards list
  94.      */
  95.     public List<IDashboardComponent> getAllDashboardComponents( )
  96.     {
  97.         return DashboardFactory.getAllDashboardComponents( );
  98.     }

  99.     /**
  100.      *
  101.      * @param nColumn
  102.      *            the column id
  103.      * @return all dashboards for this column
  104.      */
  105.     public List<IDashboardComponent> getDashboardComponents( int nColumn )
  106.     {
  107.         DashboardFilter filter = new DashboardFilter( );
  108.         filter.setFilterColumn( nColumn );

  109.         return DashboardHome.findByFilter( filter );
  110.     }

  111.     /**
  112.      * Register a Dashboard Component
  113.      *
  114.      * @param entry
  115.      *            The DashboardComponent entry defined in the plugin's XML file
  116.      * @param plugin
  117.      *            The plugin
  118.      */
  119.     public void registerDashboardComponent( DashboardComponentEntry entry, Plugin plugin )
  120.     {
  121.         try
  122.         {
  123.             DashboardComponent dc = (DashboardComponent) Class.forName( entry.getComponentClass( ) ).newInstance( );

  124.             dc.setName( entry.getName( ) );
  125.             dc.setRight( entry.getRight( ) );
  126.             dc.setPlugin( plugin );

  127.             boolean bRegistered = DashboardFactory.registerDashboardComponent( dc );

  128.             if ( bRegistered )
  129.             {
  130.                 AppLogService.info( "New Dashboard Component registered : " + entry.getName( ) );
  131.             }
  132.             else
  133.             {
  134.                 AppLogService.error( " Dashboard Component not registered : " + entry.getName( ) + " : " + entry.getComponentClass( ) );
  135.             }
  136.         }
  137.         catch( ClassNotFoundException | IllegalAccessException | InstantiationException e )
  138.         {
  139.             AppLogService.error( "Error registering a DashboardComponent : " + e.getMessage( ), e );
  140.         }
  141.     }

  142.     /**
  143.      * Moves the dashboard.
  144.      *
  145.      * @param dashboard
  146.      *            to move, with new values
  147.      * @param nOldColumn
  148.      *            previous column id
  149.      * @param nOldOrder
  150.      *            previous order
  151.      * @param bCreate
  152.      *            <code>true</code> if this is a new dashboard, <code>false</code> otherwise.
  153.      */
  154.     public void doMoveDashboard( IDashboardComponent dashboard, int nOldColumn, int nOldOrder, boolean bCreate )
  155.     {
  156.         int nColumn = dashboard.getZone( );
  157.         int nOrder = dashboard.getOrder( );

  158.         // find the dashboard already with this order and column
  159.         DashboardFilter filter = new DashboardFilter( );
  160.         filter.setFilterColumn( nColumn );

  161.         List<IDashboardComponent> listColumnDashboards = DashboardHome.findByFilter( filter );

  162.         if ( CollectionUtils.isNotEmpty( listColumnDashboards ) )
  163.         {
  164.             if ( AppLogService.isDebugEnabled( ) )
  165.             {
  166.                 AppLogService.debug( "Reordering  dashboard column " + dashboard.getZone( ) );
  167.             }

  168.             // sort by order
  169.             Collections.sort( listColumnDashboards );

  170.             int nMaxOrder = listColumnDashboards.get( listColumnDashboards.size( ) - 1 ).getOrder( );

  171.             if ( ( nOldColumn == 0 ) || ( nOldColumn != nColumn ) )
  172.             {
  173.                 // was not in this column before, put to the end
  174.                 dashboard.setOrder( nMaxOrder + 1 );
  175.             }
  176.             else
  177.             {
  178.                 updateDashboardComponents( dashboard, listColumnDashboards, nOldOrder );

  179.                 // dashboard are singletons, values are modified by getting it from database
  180.                 dashboard.setOrder( nOrder );
  181.                 dashboard.setZone( nColumn );
  182.             }
  183.         }
  184.         else
  185.         {
  186.             dashboard.setOrder( 1 );
  187.         }

  188.         if ( bCreate )
  189.         {
  190.             // create dashboard
  191.             DashboardHome.create( dashboard );
  192.         }
  193.         else
  194.         {
  195.             // update dashboard
  196.             DashboardHome.update( dashboard );
  197.         }
  198.     }

  199.     private void updateDashboardComponents( IDashboardComponent dashboard, List<IDashboardComponent> listColumnDashboards, int nOldOrder )
  200.     {
  201.         int nOrder = dashboard.getOrder( );
  202.         for ( IDashboardComponent dc : listColumnDashboards )
  203.         {
  204.             if ( dc.equals( dashboard ) )
  205.             {
  206.                 continue;
  207.             }

  208.             if ( nOrder < nOldOrder )
  209.             {
  210.                 int nCurrentOrder = dc.getOrder( );

  211.                 if ( ( nCurrentOrder >= nOrder ) && ( nCurrentOrder < nOldOrder ) )
  212.                 {
  213.                     dc.setOrder( nCurrentOrder + 1 );
  214.                     DashboardHome.update( dc );
  215.                 }
  216.             }
  217.             else
  218.                 if ( nOrder > nOldOrder )
  219.                 {
  220.                     int nCurrentOrder = dc.getOrder( );

  221.                     if ( ( nCurrentOrder <= nOrder ) && ( nCurrentOrder > nOldOrder ) )
  222.                     {
  223.                         dc.setOrder( nCurrentOrder - 1 );
  224.                         DashboardHome.update( dc );
  225.                     }
  226.                 }
  227.         }
  228.     }

  229.     /**
  230.      * Returns all dashboards with no column/order set
  231.      *
  232.      * @return all dashboards with no column/order set
  233.      */
  234.     public List<IDashboardComponent> getNotSetDashboards( )
  235.     {
  236.         List<IDashboardComponent> listDashboards = DashboardHome.findAll( );
  237.         List<IDashboardComponent> listSpringDashboards = getAllDashboardComponents( );

  238.         List<IDashboardComponent> listUnsetDashboards = new ArrayList<>( );

  239.         for ( IDashboardComponent dashboard : listSpringDashboards )
  240.         {
  241.             if ( !listDashboards.contains( dashboard ) )
  242.             {
  243.                 listUnsetDashboards.add( dashboard );
  244.             }
  245.         }

  246.         return listUnsetDashboards;
  247.     }

  248.     /**
  249.      * Finds all dashboard with column and order set.
  250.      *
  251.      * @param user
  252.      *            the current user
  253.      * @return a map where key is the column id, and value is the column's dashboard list.
  254.      */
  255.     public Map<String, List<IDashboardComponent>> getAllSetDashboards( AdminUser user )
  256.     {
  257.         Map<String, List<IDashboardComponent>> mapDashboardComponents = new HashMap<>( );

  258.         List<IDashboardComponent> listDashboards = DashboardHome.findAll( );

  259.         for ( IDashboardComponent dashboard : listDashboards )
  260.         {
  261.             int nColumn = dashboard.getZone( );
  262.             boolean bRight = user.checkRight( dashboard.getRight( ) ) || dashboard.getRight( ).equalsIgnoreCase( ALL );

  263.             if ( !bRight )
  264.             {
  265.                 continue;
  266.             }

  267.             String strColumn = Integer.toString( nColumn );

  268.             // find this column list
  269.             List<IDashboardComponent> listDashboardsColumn = mapDashboardComponents.computeIfAbsent( strColumn, s -> new ArrayList<>( ) );

  270.             // add dashboard to the list
  271.             listDashboardsColumn.add( dashboard );
  272.         }

  273.         return mapDashboardComponents;
  274.     }

  275.     /**
  276.      * Gets Data from all components of the zone
  277.      *
  278.      * @param user
  279.      *            The user
  280.      * @param nZone
  281.      *            The dasboard zone
  282.      * @param request
  283.      *            HttpServletRequest
  284.      * @return Data of all components of the zone
  285.      */
  286.     public String getDashboardData( AdminUser user, int nZone, HttpServletRequest request )
  287.     {
  288.         StringBuilder sbDashboardData = new StringBuilder( );

  289.         for ( IDashboardComponent dc : getDashboardComponents( nZone ) )
  290.         {
  291.             boolean bRight = user.checkRight( dc.getRight( ) ) || dc.getRight( ).equalsIgnoreCase( ALL );

  292.             if ( ( dc.getZone( ) == nZone ) && dc.isEnabled( ) && bRight )
  293.             {
  294.                 sbDashboardData.append( dc.getDashboardData( user, request ) );
  295.             }
  296.         }

  297.         return sbDashboardData.toString( );
  298.     }

  299.     /**
  300.      * Get the list of dashboard from plugins
  301.      *
  302.      * @param user
  303.      *            the current user
  304.      * @param request
  305.      *            HttpServletRequest
  306.      * @return the list of dashboards
  307.      */
  308.     public List<IDashboardComponent> getDashboards( AdminUser user, HttpServletRequest request )
  309.     {
  310.         List<IDashboardComponent> listDashboards = new ArrayList<>( );

  311.         // Attributes associated to the plugins
  312.         for ( DashboardListenerService dashboardListenerService : SpringContextService.getBeansOfType( DashboardListenerService.class ) )
  313.         {
  314.             dashboardListenerService.getDashboardComponents( listDashboards, user, request );
  315.         }

  316.         return listDashboards;
  317.     }

  318.     /**
  319.      * Gets Data from all components of the zone
  320.      *
  321.      * @param listDashboards
  322.      *            the list of dashboards
  323.      * @param user
  324.      *            The user
  325.      * @param nZone
  326.      *            The dasboard zone
  327.      * @param request
  328.      *            HttpServletRequest
  329.      * @return Data of all components of the zone
  330.      */
  331.     public String getDashboardData( List<IDashboardComponent> listDashboards, AdminUser user, int nZone, HttpServletRequest request )
  332.     {
  333.         List<IDashboardComponent> listDashboardComponents = new ArrayList<>( );

  334.         for ( IDashboardComponent dc : listDashboards )
  335.         {
  336.             if ( dc.getZone( ) == nZone )
  337.             {
  338.                 listDashboardComponents.add( dc );
  339.             }
  340.         }

  341.         Collections.sort( listDashboardComponents, new AttributeComparator( ORDER, true ) );

  342.         StringBuilder sbDashboardData = new StringBuilder( );

  343.         for ( IDashboardComponent dc : listDashboardComponents )
  344.         {
  345.             boolean bRight = user.checkRight( dc.getRight( ) ) || dc.getRight( ).equalsIgnoreCase( ALL );

  346.             if ( ( dc.getZone( ) == nZone ) && dc.isEnabled( ) && bRight )
  347.             {
  348.                 sbDashboardData.append( dc.getDashboardData( user, request ) );
  349.             }
  350.         }

  351.         return sbDashboardData.toString( );
  352.     }

  353.     /**
  354.      * Reorders column's dashboard
  355.      *
  356.      * @param nColumn
  357.      *            the column to reorder
  358.      */
  359.     public void doReorderColumn( int nColumn )
  360.     {
  361.         int nOrder = CONSTANTE_FIRST_ORDER;

  362.         for ( IDashboardComponent dc : getDashboardComponents( nColumn ) )
  363.         {
  364.             dc.setOrder( nOrder++ );
  365.             DashboardHome.update( dc );
  366.         }
  367.     }

  368.     /**
  369.      * Builds the map to with column id as key, and <code>true</code> as value if column is well ordered, <code>false</code> otherwise.
  370.      *
  371.      * @return the map
  372.      */
  373.     public Map<String, Boolean> getOrderedColumnsStatus( )
  374.     {
  375.         Map<String, Boolean> mapOrderedStatus = new HashMap<>( );
  376.         List<Integer> listColumns = DashboardHome.findColumns( );

  377.         for ( Integer nIdColumn : listColumns )
  378.         {
  379.             mapOrderedStatus.put( nIdColumn.toString( ), isWellOrdered( nIdColumn ) );
  380.         }

  381.         return mapOrderedStatus;
  382.     }

  383.     /**
  384.      * Determines if the column is well ordered
  385.      *
  386.      * @param nColumn
  387.      *            the column id
  388.      * @return true if well ordered, <code>false</code> otherwise.
  389.      */
  390.     private boolean isWellOrdered( int nColumn )
  391.     {
  392.         int nOrder = CONSTANTE_FIRST_ORDER;

  393.         for ( IDashboardComponent dc : getDashboardComponents( nColumn ) )
  394.         {
  395.             if ( nOrder != dc.getOrder( ) )
  396.             {
  397.                 return false;
  398.             }

  399.             nOrder++;
  400.         }

  401.         return true;
  402.     }

  403.     /**
  404.      * Returns list with available column
  405.      *
  406.      * @return all available columns
  407.      */
  408.     public ReferenceList getListAvailableColumns( )
  409.     {
  410.         ReferenceList refList = new ReferenceList( );

  411.         // add empty item
  412.         refList.addItem( EMPTY_STRING, EMPTY_STRING );

  413.         for ( int nColumnIndex = 1; nColumnIndex <= getColumnCount( ); nColumnIndex++ )
  414.         {
  415.             refList.addItem( nColumnIndex, Integer.toString( nColumnIndex ) );
  416.         }

  417.         return refList;
  418.     }

  419.     /**
  420.      * Builds all refList order for all columns
  421.      *
  422.      * @return the map with column id as key
  423.      */
  424.     public Map<String, ReferenceList> getMapAvailableOrders( )
  425.     {
  426.         Map<String, ReferenceList> mapAvailableOrders = new HashMap<>( );

  427.         // get columns
  428.         for ( Integer nColumn : DashboardHome.findColumns( ) )
  429.         {
  430.             // get orders
  431.             mapAvailableOrders.put( nColumn.toString( ), getListAvailableOrders( nColumn ) );
  432.         }

  433.         return mapAvailableOrders;
  434.     }

  435.     /**
  436.      * Orders reference list for the given column
  437.      *
  438.      * @param nColumn
  439.      *            column
  440.      * @return the refList
  441.      */
  442.     public ReferenceList getListAvailableOrders( int nColumn )
  443.     {
  444.         ReferenceList refList = new ReferenceList( );

  445.         // add empty item
  446.         refList.addItem( EMPTY_STRING, EMPTY_STRING );

  447.         int nMaxOrder = DashboardHome.findMaxOrder( nColumn );

  448.         for ( int nOrder = 1; nOrder <= nMaxOrder; nOrder++ )
  449.         {
  450.             refList.addItem( nOrder, Integer.toString( nOrder ) );
  451.         }

  452.         return refList;
  453.     }
  454. }