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