1 /*
2  * Copyright (C) 2005-2008 Jive Software. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.jivesoftware.openfire.container;
18 
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 
25 import org.jivesoftware.util.JiveConstants;
26 import org.jivesoftware.util.cache.CacheFactory;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 
30 /**
31  * A simple registry of cache configuration data for plugins.
32  */
33 public class PluginCacheRegistry {
34 
35     private static final Logger Log = LoggerFactory.getLogger(PluginCacheRegistry.class);
36 
37     private static final PluginCacheRegistry instance = new PluginCacheRegistry();
38 
39     private Map<String, CacheInfo> extraCacheMappings = new HashMap<>();
40     private Map<String, List<CacheInfo>> pluginCaches = new HashMap<>();
41 
getInstance()42     public static PluginCacheRegistry getInstance() {
43         return instance;
44     }
45 
PluginCacheRegistry()46     private PluginCacheRegistry() {
47     }
48 
49     /**
50      * Registers cache configuration data for a give cache and plugin.
51      *
52      * @param pluginName the name of the plugin which will use the cache.
53      * @param info the cache configuration data.
54      */
registerCache(String pluginName, CacheInfo info)55     public void registerCache(String pluginName, CacheInfo info) {
56         extraCacheMappings.put(info.getCacheName(), info);
57         List<CacheInfo> caches = pluginCaches.get(pluginName);
58 
59         if (caches == null) {
60             caches = new ArrayList<>();
61             pluginCaches.put(pluginName, caches);
62         }
63 
64         caches.add(info);
65 
66         // Set system properties for this cache
67         CacheFactory.setCacheTypeProperty(info.getCacheName(), info.getType().getName());
68         CacheFactory.setMaxSizeProperty(info.getCacheName(), getMaxSizeFromProperty(info));
69         CacheFactory.setMaxLifetimeProperty(info.getCacheName(), getMaxLifetimeFromProperty(info));
70         CacheFactory.setMinCacheSize(info.getCacheName(), getMinSizeFromProperty(info));
71     }
72 
73     /**
74      * Unregisters all caches for the given plugin.
75      *
76      * @param pluginName the name of the plugin whose caches will be unregistered.
77      */
unregisterCaches(String pluginName)78     public void unregisterCaches(String pluginName) {
79         List<CacheInfo> caches = pluginCaches.remove(pluginName);
80         if (caches != null) {
81             for (CacheInfo info : caches) {
82                 extraCacheMappings.remove(info.getCacheName());
83                 // Check if other cluster nodes have this plugin installed
84                 Collection<Boolean> answers =
85                         CacheFactory.doSynchronousClusterTask(new IsPluginInstalledTask(pluginName), false);
86                 for (Boolean installed : answers) {
87                     if (installed) {
88                         return;
89                     }
90                 }
91                 // Destroy cache if we are the last node hosting this plugin
92                 try {
93                     CacheFactory.destroyCache(info.getCacheName());
94                 }
95                 catch (Exception e) {
96                     Log.warn(e.getMessage(), e);
97                 }
98             }
99         }
100     }
101 
getCacheInfo(String name)102     public CacheInfo getCacheInfo(String name) {
103         return extraCacheMappings.get(name);
104     }
105 
getMaxSizeFromProperty(CacheInfo cacheInfo)106     private long getMaxSizeFromProperty(CacheInfo cacheInfo) {
107         String sizeProp = cacheInfo.getParams().get("back-size-high");
108         if (sizeProp != null) {
109             if ("0".equals(sizeProp)) {
110                 return -1L;
111             }
112             try {
113                 return Integer.parseInt(sizeProp);
114             }
115             catch (NumberFormatException nfe) {
116                 Log.warn("Unable to parse back-size-high for cache: " + cacheInfo.getCacheName());
117             }
118         }
119         // Return default
120         return CacheFactory.DEFAULT_MAX_CACHE_SIZE;
121     }
122 
getMaxLifetimeFromProperty(CacheInfo cacheInfo)123     private static long getMaxLifetimeFromProperty(CacheInfo cacheInfo) {
124         String lifetimeProp = cacheInfo.getParams().get("back-expiry");
125         if (lifetimeProp != null) {
126             if ("0".equals(lifetimeProp)) {
127                 return -1L;
128             }
129             long factor = 1;
130             if (lifetimeProp.endsWith("m")) {
131                 factor = JiveConstants.MINUTE;
132             }
133             else if (lifetimeProp.endsWith("h")) {
134                 factor = JiveConstants.HOUR;
135             }
136             else if (lifetimeProp.endsWith("d")) {
137                 factor = JiveConstants.DAY;
138             }
139             try {
140                 return Long.parseLong(lifetimeProp.substring(0, lifetimeProp.length()-1)) * factor;
141             }
142             catch (NumberFormatException nfe) {
143                 Log.warn("Unable to parse back-expiry for cache: " + cacheInfo.getCacheName());
144             }
145         }
146         // Return default
147         return CacheFactory.DEFAULT_MAX_CACHE_LIFETIME;
148     }
149 
getMinSizeFromProperty(CacheInfo cacheInfo)150     private long getMinSizeFromProperty(CacheInfo cacheInfo) {
151         String sizeProp = cacheInfo.getParams().get("back-size-low");
152         if (sizeProp != null) {
153             if ("0".equals(sizeProp)) {
154                 return -1L;
155             }
156             try {
157                 return Integer.parseInt(sizeProp);
158             }
159             catch (NumberFormatException nfe) {
160                 Log.warn("Unable to parse back-size-low for cache: " + cacheInfo.getCacheName());
161             }
162         }
163         // Return default
164         return CacheFactory.DEFAULT_MAX_CACHE_SIZE;
165     }
166 }
167