DatastoreService.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.datastore;

  35. import fr.paris.lutece.portal.business.datastore.DataEntity;
  36. import fr.paris.lutece.portal.business.datastore.DataEntityHome;
  37. import fr.paris.lutece.portal.service.template.FreeMarkerTemplateService;
  38. import fr.paris.lutece.portal.service.util.AppLogService;
  39. import fr.paris.lutece.portal.service.util.AppPathService;
  40. import fr.paris.lutece.portal.service.util.NoDatabaseException;
  41. import fr.paris.lutece.util.ReferenceList;

  42. import java.util.List;
  43. import java.util.regex.Matcher;
  44. import java.util.regex.Pattern;

  45. /**
  46.  * Datastore Service
  47.  */
  48. public final class DatastoreService
  49. {
  50.     public static final String VALUE_TRUE = "true";
  51.     public static final String VALUE_FALSE = "false";
  52.     private static final String DATASTORE_KEY = "dskey";
  53.     private static final Pattern PATTERN_DATASTORE_KEY = Pattern.compile( "#" + DATASTORE_KEY + "\\{(.*?)\\}" );
  54.     static final String VALUE_MISSING = "DS Value Missing";
  55.     private static DatastoreCacheService _cache;
  56.     private static boolean _bDatabase = true;

  57.     /**
  58.      * Private constructor
  59.      */
  60.     private DatastoreService( )
  61.     {
  62.     }

  63.     /**
  64.      * initialize the service
  65.      */
  66.     public static void init( )
  67.     {
  68.         FreeMarkerTemplateService.getInstance( ).setSharedVariable( DATASTORE_KEY, new DatastoreTemplateMethod( ) );
  69.     }

  70.     /**
  71.      * Get entity
  72.      *
  73.      * @param strKey
  74.      *            The entity's key
  75.      * @param strDefault
  76.      *            The default value
  77.      * @return The value
  78.      */
  79.     public static String getDataValue( String strKey, String strDefault )
  80.     {
  81.         try
  82.         {
  83.             if ( _bDatabase )
  84.             {
  85.                 DataEntity entity = null;

  86.                 if ( _cache != null )
  87.                 {
  88.                     entity = (DataEntity) _cache.getFromCache( _cache.getEntityCacheKey( strKey ) );
  89.                 }

  90.                 if ( entity == null )
  91.                 {
  92.                     entity = DataEntityHome.findByPrimaryKey( strKey );

  93.                     if ( entity == null )
  94.                     {
  95.                         return strDefault;
  96.                     }

  97.                     if ( _cache != null )
  98.                     {
  99.                         _cache.putInCache( _cache.getEntityCacheKey( strKey ), entity );
  100.                     }
  101.                 }

  102.                 return entity.getValue( );
  103.             }
  104.         }
  105.         catch( NoDatabaseException e )
  106.         {
  107.             disableDatastore( e );
  108.         }

  109.         return strDefault;
  110.     }

  111.     /**
  112.      * Get entity depending the current web app instance
  113.      *
  114.      * @param strKey
  115.      *            The entity's key
  116.      * @param strDefault
  117.      *            The default value
  118.      * @return The value
  119.      */
  120.     public static String getInstanceDataValue( String strKey, String strDefault )
  121.     {
  122.         String strInstanceKey = getInstanceKey( strKey );

  123.         return getDataValue( strInstanceKey, strDefault );
  124.     }

  125.     /**
  126.      * Set entity
  127.      *
  128.      * @param strKey
  129.      *            The entity's key
  130.      * @param strValue
  131.      *            The value
  132.      */
  133.     public static void setDataValue( String strKey, String strValue )
  134.     {
  135.         try
  136.         {
  137.             if ( _bDatabase )
  138.             {
  139.                 DataEntity p = new DataEntity( strKey, strValue );
  140.                 DataEntity entity = DataEntityHome.findByPrimaryKey( strKey );

  141.                 if ( entity != null )
  142.                 {
  143.                     DataEntityHome.update( p );

  144.                     if ( _cache != null )
  145.                     {
  146.                         _cache.removeKey( _cache.getEntityCacheKey( strKey ) );
  147.                         _cache.removeCachedPrefixes( );
  148.                     }
  149.                 }
  150.                 else
  151.                 {
  152.                     DataEntityHome.create( p );
  153.                     if ( _cache != null )
  154.                     {
  155.                         _cache.removeCachedPrefixes( );
  156.                     }
  157.                 }
  158.             }
  159.         }
  160.         catch( NoDatabaseException e )
  161.         {
  162.             disableDatastore( e );
  163.         }
  164.     }

  165.     /**
  166.      * Set entity depending the current web app instance
  167.      *
  168.      * @param strKey
  169.      *            The entity's key
  170.      * @param strValue
  171.      *            The value
  172.      */
  173.     public static void setInstanceDataValue( String strKey, String strValue )
  174.     {
  175.         String strInstanceKey = getInstanceKey( strKey );
  176.         setDataValue( strInstanceKey, strValue );
  177.     }

  178.     /**
  179.      * Remove a give key
  180.      *
  181.      * @param strKey
  182.      *            The key
  183.      */
  184.     public static void removeData( String strKey )
  185.     {
  186.         try
  187.         {
  188.             if ( _bDatabase )
  189.             {
  190.                 DataEntityHome.remove( strKey );

  191.                 if ( _cache != null )
  192.                 {
  193.                     _cache.removeKey( _cache.getEntityCacheKey( strKey ) );
  194.                     _cache.removeCachedPrefixes( );
  195.                 }
  196.             }
  197.         }
  198.         catch( NoDatabaseException e )
  199.         {
  200.             disableDatastore( e );
  201.         }
  202.     }

  203.     /**
  204.      * Remove a give key depending the current web app instance
  205.      *
  206.      * @param strKey
  207.      *            The key
  208.      */
  209.     public static void removeInstanceData( String strKey )
  210.     {
  211.         String strInstanceKey = getInstanceKey( strKey );
  212.         removeData( strInstanceKey );
  213.     }

  214.     /**
  215.      * Remove all data where keys begin with a given prefix
  216.      *
  217.      * @param strPrefix
  218.      *            The prefix
  219.      */
  220.     public static void removeDataByPrefix( String strPrefix )
  221.     {
  222.         try
  223.         {
  224.             if ( _bDatabase )
  225.             {
  226.                 List<DataEntity> listEntities = DataEntityHome.findAll( );

  227.                 for ( DataEntity entity : listEntities )
  228.                 {
  229.                     if ( entity.getKey( ).startsWith( strPrefix ) )
  230.                     {
  231.                         removeData( entity.getKey( ) );
  232.                     }
  233.                 }
  234.             }
  235.         }
  236.         catch( NoDatabaseException e )
  237.         {
  238.             disableDatastore( e );
  239.         }
  240.     }

  241.     /**
  242.      * Remove all data where keys begin with a given prefix depending the current web app instance
  243.      *
  244.      * @param strPrefix
  245.      *            The prefix
  246.      */
  247.     public static void removeInstanceDataByPrefix( String strPrefix )
  248.     {
  249.         String strInstancePrefix = getInstanceKey( strPrefix );
  250.         removeDataByPrefix( strInstancePrefix );
  251.     }

  252.     /**
  253.      * Gets a list of key/value where keys are matching a given prefix
  254.      *
  255.      * @param strPrefix
  256.      *            The prefix
  257.      * @return The list
  258.      */
  259.     public static ReferenceList getDataByPrefix( String strPrefix )
  260.     {
  261.         if ( !_bDatabase )
  262.         {
  263.             return new ReferenceList( );
  264.         }
  265.         try
  266.         {
  267.             ReferenceList list = null;

  268.             if ( _cache != null )
  269.             {
  270.                 list = ( ReferenceList ) _cache.getFromCache( _cache.getPrefixCacheKey( strPrefix ) );
  271.             }

  272.             if ( list == null )
  273.             {
  274.                 list = new ReferenceList( );
  275.                 for ( DataEntity entity : DataEntityHome.findByPrefix( strPrefix ) )
  276.                 {
  277.                     list.addItem( entity.getKey( ), entity.getValue( ) );
  278.                 }

  279.                 if ( _cache != null )
  280.                 {
  281.                     _cache.putInCache( _cache.getPrefixCacheKey( strPrefix ), list );
  282.                 }
  283.             }

  284.             return list;
  285.         }
  286.         catch ( NoDatabaseException e )
  287.         {
  288.             disableDatastore( e );
  289.         }

  290.         return new ReferenceList( );
  291.     }

  292.     /**
  293.      * Gets a list of key/value where keys are matching a given prefix depending the current web app instance
  294.      *
  295.      * @param strPrefix
  296.      *            The prefix
  297.      * @return The list
  298.      */
  299.     public static ReferenceList getInstanceDataByPrefix( String strPrefix )
  300.     {
  301.         String strInstancePrefix = getInstanceKey( strPrefix );

  302.         return getDataByPrefix( strInstancePrefix );
  303.     }

  304.     /**
  305.      * This method replace keys by their value into a given content
  306.      *
  307.      * @param strSource
  308.      *            The string that contains datastore keys
  309.      * @return The string with keys replaced
  310.      */
  311.     public static String replaceKeys( String strSource )
  312.     {
  313.         String result = strSource;

  314.         if ( strSource != null )
  315.         {
  316.             Matcher matcher = PATTERN_DATASTORE_KEY.matcher( strSource );

  317.             if ( matcher.find( ) )
  318.             {
  319.                 StringBuffer sb = new StringBuffer( );

  320.                 do
  321.                 {
  322.                     String strKey = matcher.group( 1 );
  323.                     String strValue = DatastoreService.getDataValue( strKey, VALUE_MISSING );

  324.                     if ( VALUE_MISSING.equals( strValue ) )
  325.                     {
  326.                         AppLogService.error( "Datastore Key missing : {} - Please fix to avoid performance issues.", strKey );
  327.                     }

  328.                     matcher.appendReplacement( sb, strValue );
  329.                 }
  330.                 while ( matcher.find( ) );

  331.                 matcher.appendTail( sb );
  332.                 result = sb.toString( );
  333.             }
  334.         }

  335.         return result;
  336.     }

  337.     /**
  338.      * Check if a key is available in the datastore
  339.      *
  340.      * @param strKey
  341.      *            The key
  342.      * @return True if the key is found otherwise false
  343.      */
  344.     public static boolean existsKey( String strKey )
  345.     {
  346.         try
  347.         {
  348.             if ( _bDatabase )
  349.             {
  350.                 DataEntity entity = null;

  351.                 if ( _cache != null )
  352.                 {
  353.                     entity = (DataEntity) _cache.getFromCache( _cache.getEntityCacheKey( strKey ) );
  354.                 }

  355.                 if ( entity == null )
  356.                 {
  357.                     entity = DataEntityHome.findByPrimaryKey( strKey );

  358.                     if ( entity == null )
  359.                     {
  360.                         return false;
  361.                     }
  362.                 }

  363.                 return true;
  364.             }
  365.         }
  366.         catch( NoDatabaseException e )
  367.         {
  368.             disableDatastore( e );
  369.         }

  370.         return false;
  371.     }

  372.     /**
  373.      * Check if a key is available in the datastore depending the current web app instance
  374.      *
  375.      * @param strKey
  376.      *            The key
  377.      * @return True if the key is found otherwise false
  378.      */
  379.     public static boolean existsInstanceKey( String strKey )
  380.     {
  381.         String strInstanceKey = getInstanceKey( strKey );

  382.         return existsKey( strInstanceKey );
  383.     }

  384.     /**
  385.      * Start cache. NB : Cache can't be created at DataStore creation because CacheService uses DatastoreService (Circular reference)
  386.      */
  387.     public static void startCache( )
  388.     {
  389.         _cache = new DatastoreCacheService( );
  390.         AppLogService.info( "Datastore's cache started." );
  391.     }

  392.     /**
  393.      * Disable the Datastore if a NoDatabaseException is catched
  394.      *
  395.      * @param e
  396.      *            The NoDatabaseException
  397.      */
  398.     private static void disableDatastore( NoDatabaseException e )
  399.     {
  400.         _bDatabase = false;
  401.         AppLogService.error( "##### CRITICAL ERROR ##### : Datastore has been disabled due to a NoDatabaseException catched", e );
  402.     }

  403.     /**
  404.      * Return a datastore key for the current webapp instance
  405.      *
  406.      * @param strKey
  407.      *            The key
  408.      * @return The key for the current instance
  409.      */
  410.     private static String getInstanceKey( String strKey )
  411.     {
  412.         if ( !AppPathService.isDefaultWebappInstance( ) )
  413.         {
  414.             StringBuilder sbInstanceKey = new StringBuilder( );
  415.             sbInstanceKey.append( AppPathService.getWebappInstance( ) ).append( "." ).append( strKey );

  416.             return sbInstanceKey.toString( );
  417.         }

  418.         return strKey;
  419.     }
  420. }