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.datastore;
35  
36  import fr.paris.lutece.portal.business.datastore.DataEntity;
37  import fr.paris.lutece.portal.business.datastore.DataEntityHome;
38  import fr.paris.lutece.portal.service.cache.AbstractCacheableService;
39  import fr.paris.lutece.portal.service.template.FreeMarkerTemplateService;
40  import fr.paris.lutece.portal.service.util.AppLogService;
41  import fr.paris.lutece.portal.service.util.AppPathService;
42  import fr.paris.lutece.portal.service.util.NoDatabaseException;
43  import fr.paris.lutece.util.ReferenceList;
44  
45  import java.util.List;
46  import java.util.regex.Matcher;
47  import java.util.regex.Pattern;
48  
49  /**
50   * Datastore Service
51   */
52  public final class DatastoreService
53  {
54      public static final String VALUE_TRUE = "true";
55      public static final String VALUE_FALSE = "false";
56      private static final String DATASTORE_KEY = "dskey";
57      private static final Pattern PATTERN_DATASTORE_KEY = Pattern.compile( "#" + DATASTORE_KEY + "\\{(.*?)\\}" );
58      static final String VALUE_MISSING = "DS Value Missing";
59      private static AbstractCacheableService _cache;
60      private static boolean _bDatabase = true;
61  
62      /**
63       * Private constructor
64       */
65      private DatastoreService( )
66      {
67      }
68  
69      /**
70       * initialize the service
71       */
72      public static void init( )
73      {
74          FreeMarkerTemplateService.getInstance( ).setSharedVariable( DATASTORE_KEY, new DatastoreTemplateMethod( ) );
75      }
76  
77      /**
78       * Get entity
79       *
80       * @param strKey
81       *            The entity's key
82       * @param strDefault
83       *            The default value
84       * @return The value
85       */
86      public static String getDataValue( String strKey, String strDefault )
87      {
88          try
89          {
90              if ( _bDatabase )
91              {
92                  DataEntity entity = null;
93  
94                  if ( _cache != null )
95                  {
96                      entity = (DataEntity) _cache.getFromCache( strKey );
97                  }
98  
99                  if ( entity == null )
100                 {
101                     entity = DataEntityHome.findByPrimaryKey( strKey );
102 
103                     if ( entity == null )
104                     {
105                         return strDefault;
106                     }
107 
108                     if ( _cache != null )
109                     {
110                         _cache.putInCache( strKey, entity );
111                     }
112                 }
113 
114                 return entity.getValue( );
115             }
116         }
117         catch( NoDatabaseException e )
118         {
119             disableDatastore( e );
120         }
121 
122         return strDefault;
123     }
124 
125     /**
126      * Get entity depending the current web app instance
127      *
128      * @param strKey
129      *            The entity's key
130      * @param strDefault
131      *            The default value
132      * @return The value
133      */
134     public static String getInstanceDataValue( String strKey, String strDefault )
135     {
136         String strInstanceKey = getInstanceKey( strKey );
137 
138         return getDataValue( strInstanceKey, strDefault );
139     }
140 
141     /**
142      * Set entity
143      *
144      * @param strKey
145      *            The entity's key
146      * @param strValue
147      *            The value
148      */
149     public static void setDataValue( String strKey, String strValue )
150     {
151         try
152         {
153             if ( _bDatabase )
154             {
155                 DataEntityl/business/datastore/DataEntity.html#DataEntity">DataEntity p = new DataEntity( strKey, strValue );
156                 DataEntity entity = DataEntityHome.findByPrimaryKey( strKey );
157 
158                 if ( entity != null )
159                 {
160                     DataEntityHome.update( p );
161 
162                     if ( _cache != null )
163                     {
164                         _cache.removeKey( strKey );
165                     }
166                 }
167                 else
168                 {
169                     DataEntityHome.create( p );
170                 }
171             }
172         }
173         catch( NoDatabaseException e )
174         {
175             disableDatastore( e );
176         }
177     }
178 
179     /**
180      * Set entity depending the current web app instance
181      *
182      * @param strKey
183      *            The entity's key
184      * @param strValue
185      *            The value
186      */
187     public static void setInstanceDataValue( String strKey, String strValue )
188     {
189         String strInstanceKey = getInstanceKey( strKey );
190         setDataValue( strInstanceKey, strValue );
191     }
192 
193     /**
194      * Remove a give key
195      *
196      * @param strKey
197      *            The key
198      */
199     public static void removeData( String strKey )
200     {
201         try
202         {
203             if ( _bDatabase )
204             {
205                 DataEntityHome.remove( strKey );
206 
207                 if ( _cache != null )
208                 {
209                     _cache.removeKey( strKey );
210                 }
211             }
212         }
213         catch( NoDatabaseException e )
214         {
215             disableDatastore( e );
216         }
217     }
218 
219     /**
220      * Remove a give key depending the current web app instance
221      *
222      * @param strKey
223      *            The key
224      */
225     public static void removeInstanceData( String strKey )
226     {
227         String strInstanceKey = getInstanceKey( strKey );
228         removeData( strInstanceKey );
229     }
230 
231     /**
232      * Remove all data where keys begin with a given prefix
233      *
234      * @param strPrefix
235      *            The prefix
236      */
237     public static void removeDataByPrefix( String strPrefix )
238     {
239         try
240         {
241             if ( _bDatabase )
242             {
243                 List<DataEntity> listEntities = DataEntityHome.findAll( );
244 
245                 for ( DataEntity entity : listEntities )
246                 {
247                     if ( entity.getKey( ).startsWith( strPrefix ) )
248                     {
249                         removeData( entity.getKey( ) );
250                     }
251                 }
252             }
253         }
254         catch( NoDatabaseException e )
255         {
256             disableDatastore( e );
257         }
258     }
259 
260     /**
261      * Remove all data where keys begin with a given prefix depending the current web app instance
262      *
263      * @param strPrefix
264      *            The prefix
265      */
266     public static void removeInstanceDataByPrefix( String strPrefix )
267     {
268         String strInstancePrefix = getInstanceKey( strPrefix );
269         removeDataByPrefix( strInstancePrefix );
270     }
271 
272     /**
273      * Gets a list of key/value where keys are matching a given prefix
274      *
275      * @param strPrefix
276      *            The prefix
277      * @return The list
278      */
279     public static ReferenceList getDataByPrefix( String strPrefix )
280     {
281         ReferenceListnceList.html#ReferenceList">ReferenceList list = new ReferenceList( );
282 
283         try
284         {
285             if ( _bDatabase )
286             {
287                 List<DataEntity> listEntities = DataEntityHome.findAll( );
288 
289                 for ( DataEntity entity : listEntities )
290                 {
291                     if ( entity.getKey( ).startsWith( strPrefix ) )
292                     {
293                         list.addItem( entity.getKey( ), entity.getValue( ) );
294                     }
295                 }
296             }
297         }
298         catch( NoDatabaseException e )
299         {
300             disableDatastore( e );
301         }
302 
303         return list;
304     }
305 
306     /**
307      * Gets a list of key/value where keys are matching a given prefix depending the current web app instance
308      *
309      * @param strPrefix
310      *            The prefix
311      * @return The list
312      */
313     public static ReferenceList getInstanceDataByPrefix( String strPrefix )
314     {
315         String strInstancePrefix = getInstanceKey( strPrefix );
316 
317         return getDataByPrefix( strInstancePrefix );
318     }
319 
320     /**
321      * This method replace keys by their value into a given content
322      *
323      * @param strSource
324      *            The string that contains datastore keys
325      * @return The string with keys replaced
326      */
327     public static String replaceKeys( String strSource )
328     {
329         String result = strSource;
330 
331         if ( strSource != null )
332         {
333             Matcher matcher = PATTERN_DATASTORE_KEY.matcher( strSource );
334 
335             if ( matcher.find( ) )
336             {
337                 StringBuffer sb = new StringBuffer( );
338 
339                 do
340                 {
341                     String strKey = matcher.group( 1 );
342                     String strValue = DatastoreService.getDataValue( strKey, VALUE_MISSING );
343 
344                     if ( VALUE_MISSING.equals( strValue ) )
345                     {
346                         AppLogService.error( "Datastore Key missing : {} - Please fix to avoid performance issues.", strKey );
347                     }
348 
349                     matcher.appendReplacement( sb, strValue );
350                 }
351                 while ( matcher.find( ) );
352 
353                 matcher.appendTail( sb );
354                 result = sb.toString( );
355             }
356         }
357 
358         return result;
359     }
360 
361     /**
362      * Check if a key is available in the datastore
363      *
364      * @param strKey
365      *            The key
366      * @return True if the key is found otherwise false
367      */
368     public static boolean existsKey( String strKey )
369     {
370         try
371         {
372             if ( _bDatabase )
373             {
374                 DataEntity entity = null;
375 
376                 if ( _cache != null )
377                 {
378                     entity = (DataEntity) _cache.getFromCache( strKey );
379                 }
380 
381                 if ( entity == null )
382                 {
383                     entity = DataEntityHome.findByPrimaryKey( strKey );
384 
385                     if ( entity == null )
386                     {
387                         return false;
388                     }
389                 }
390 
391                 return true;
392             }
393         }
394         catch( NoDatabaseException e )
395         {
396             disableDatastore( e );
397         }
398 
399         return false;
400     }
401 
402     /**
403      * Check if a key is available in the datastore depending the current web app instance
404      *
405      * @param strKey
406      *            The key
407      * @return True if the key is found otherwise false
408      */
409     public static boolean existsInstanceKey( String strKey )
410     {
411         String strInstanceKey = getInstanceKey( strKey );
412 
413         return existsKey( strInstanceKey );
414     }
415 
416     /**
417      * Start cache. NB : Cache can't be created at DataStore creation because CacheService uses DatastoreService (Circular reference)
418      */
419     public static void startCache( )
420     {
421         _cache = new DatastoreCacheService( );
422         AppLogService.info( "Datastore's cache started." );
423     }
424 
425     /**
426      * Disable the Datastore if a NoDatabaseException is catched
427      * 
428      * @param e
429      *            The NoDatabaseException
430      */
431     private static void disableDatastore( NoDatabaseException e )
432     {
433         _bDatabase = false;
434         AppLogService.error( "##### CRITICAL ERROR ##### : Datastore has been disabled due to a NoDatabaseException catched", e );
435     }
436 
437     /**
438      * Return a datastore key for the current webapp instance
439      * 
440      * @param strKey
441      *            The key
442      * @return The key for the current instance
443      */
444     private static String getInstanceKey( String strKey )
445     {
446         if ( !AppPathService.isDefaultWebappInstance( ) )
447         {
448             StringBuilder sbInstanceKey = new StringBuilder( );
449             sbInstanceKey.append( AppPathService.getWebappInstance( ) ).append( "." ).append( strKey );
450 
451             return sbInstanceKey.toString( );
452         }
453 
454         return strKey;
455     }
456 }