File Source: WeblogPageCache.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * 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. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.ui.rendering.util.cache;
20
21 import java.io.UnsupportedEncodingException;
22 import java.net.URLEncoder;
23 import java.util.Enumeration;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.TreeSet;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.roller.weblogger.config.WebloggerConfig;
32 import org.apache.roller.weblogger.ui.rendering.util.WeblogPageRequest;
33 import org.apache.roller.weblogger.util.Utilities;
34 import org.apache.roller.weblogger.util.cache.Cache;
35 import org.apache.roller.weblogger.util.cache.CacheManager;
36 import org.apache.roller.weblogger.util.cache.LazyExpiringCacheEntry;
37
38
39 /**
40 * Cache for weblog page content.
41 */
42 public class WeblogPageCache {
43
/*
P/P * Method: org.apache.roller.weblogger.ui.rendering.util.cache.WeblogPageCache__static_init
*
* Presumptions:
* org.apache.commons.logging.LogFactory:getLog(...)@44 != null
*
* Postconditions:
* (soft) log != null
* singletonInstance == &new WeblogPageCache(WeblogPageCache__static_init#1)
* new WeblogPageCache(WeblogPageCache__static_init#1) num objects == 1
* init'ed(singletonInstance.cacheEnabled)
* init'ed(singletonInstance.contentCache)
*/
44 private static Log log = LogFactory.getLog(WeblogPageCache.class);
45
46 // a unique identifier for this cache, this is used as the prefix for
47 // roller config properties that apply to this cache
48 public static final String CACHE_ID = "cache.weblogpage";
49
50 // keep cached content
51 private boolean cacheEnabled = true;
52 private Cache contentCache = null;
53
54 // reference to our singleton instance
55 private static WeblogPageCache singletonInstance = new WeblogPageCache();
56
57
/*
P/P * Method: void org.apache.roller.weblogger.ui.rendering.util.cache.WeblogPageCache()
*
* Preconditions:
* log != null
*
* Presumptions:
* java.lang.String:length(...)@71 <= 232-2
* java.util.Enumeration:nextElement(...)@67 != null
* org.apache.roller.weblogger.config.WebloggerConfig:keys(...)@64 != null
*
* Postconditions:
* init'ed(this.cacheEnabled)
* init'ed(this.contentCache)
*
* Test Vectors:
* java.lang.String:startsWith(...)@70: {0}, {1}
* java.util.Enumeration:hasMoreElements(...)@66: {0}, {1}
* org.apache.roller.weblogger.config.WebloggerConfig:getBooleanProperty(...)@60: {0}, {1}
*/
58 private WeblogPageCache() {
59
60 cacheEnabled = WebloggerConfig.getBooleanProperty(CACHE_ID+".enabled");
61
62 Map cacheProps = new HashMap();
63 cacheProps.put("id", CACHE_ID);
64 Enumeration allProps = WebloggerConfig.keys();
65 String prop = null;
66 while(allProps.hasMoreElements()) {
67 prop = (String) allProps.nextElement();
68
69 // we are only interested in props for this cache
70 if(prop.startsWith(CACHE_ID+".")) {
71 cacheProps.put(prop.substring(CACHE_ID.length()+1),
72 WebloggerConfig.getProperty(prop));
73 }
74 }
75
76 log.info(cacheProps);
77
78 if(cacheEnabled) {
79 contentCache = CacheManager.constructCache(null, cacheProps);
80 } else {
81 log.warn("Caching has been DISABLED");
82 }
83 }
84
85
86 public static WeblogPageCache getInstance() {
/*
P/P * Method: WeblogPageCache getInstance()
*
* Preconditions:
* init'ed(singletonInstance)
*
* Postconditions:
* return_value == singletonInstance
* init'ed(return_value)
*/
87 return singletonInstance;
88 }
89
90
91 public Object get(String key, long lastModified) {
92
/*
P/P * Method: Object get(String, long)
*
* Preconditions:
* init'ed(this.cacheEnabled)
* (soft) log != null
* (soft) this.contentCache != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* this.cacheEnabled: {1}, {0}
* org.apache.roller.weblogger.util.cache.Cache:get(...)@98: Addr_Set{null}, Inverse{null}
* org.apache.roller.weblogger.util.cache.LazyExpiringCacheEntry:getValue(...)@101: Addr_Set{null}, Inverse{null}
*/
93 if(!cacheEnabled)
94 return null;
95
96 Object entry = null;
97
98 LazyExpiringCacheEntry lazyEntry =
99 (LazyExpiringCacheEntry) this.contentCache.get(key);
100 if(lazyEntry != null) {
101 entry = lazyEntry.getValue(lastModified);
102
103 if(entry != null) {
104 log.debug("HIT "+key);
105 } else {
106 log.debug("HIT-EXPIRED "+key);
107 }
108
109 } else {
110 log.debug("MISS "+key);
111 }
112
113 return entry;
114 }
115
116
117 public void put(String key, Object value) {
118
/*
P/P * Method: void put(String, Object)
*
* Preconditions:
* init'ed(this.cacheEnabled)
* (soft) log != null
* (soft) this.contentCache != null
*
* Test Vectors:
* this.cacheEnabled: {1}, {0}
*/
119 if(!cacheEnabled)
120 return;
121
122 contentCache.put(key, new LazyExpiringCacheEntry(value));
123 log.debug("PUT "+key);
124 }
125
126
127 public void remove(String key) {
128
/*
P/P * Method: void remove(String)
*
* Preconditions:
* init'ed(this.cacheEnabled)
* (soft) log != null
* (soft) this.contentCache != null
*
* Test Vectors:
* this.cacheEnabled: {1}, {0}
*/
129 if(!cacheEnabled)
130 return;
131
132 contentCache.remove(key);
133 log.debug("REMOVE "+key);
134 }
135
136
137 public void clear() {
138
/*
P/P * Method: void clear()
*
* Preconditions:
* init'ed(this.cacheEnabled)
* (soft) log != null
* (soft) this.contentCache != null
*
* Test Vectors:
* this.cacheEnabled: {1}, {0}
*/
139 if(!cacheEnabled)
140 return;
141
142 contentCache.clear();
143 log.debug("CLEAR");
144 }
145
146
147 /**
148 * Generate a cache key from a parsed weblog page request.
149 * This generates a key of the form ...
150 *
151 * <handle>/<ctx>[/anchor][/language][/user]
152 * or
153 * <handle>/<ctx>[/weblogPage][/date][/category][/language][/user]
154 *
155 *
156 * examples ...
157 *
158 * foo/en
159 * foo/entry_anchor
160 * foo/20051110/en
161 * foo/MyCategory/en/user=myname
162 *
163 */
164 public String generateKey(WeblogPageRequest pageRequest) {
165
/*
P/P * Method: String generateKey(WeblogPageRequest)
*
* Preconditions:
* pageRequest != null
* init'ed(pageRequest.locale)
* init'ed(pageRequest.weblogAnchor)
* init'ed(pageRequest.weblogHandle)
* init'ed(pageRequest.weblogPageName)
* (soft) init'ed(pageRequest.authenticUser)
* (soft) init'ed(pageRequest.context)
* (soft) pageRequest.customParams != null
* (soft) init'ed(pageRequest.pageNum)
* (soft) init'ed(pageRequest.tags)
* ...
*
* Presumptions:
* java.util.Set:size(...)@208 >= 0
*
* Postconditions:
* init'ed(java.lang.StringBuffer:toString(...)._tainted)
* return_value == &java.lang.StringBuffer:toString(...)
*
* Test Vectors:
* pageRequest.locale: Addr_Set{null}, Inverse{null}
* pageRequest.tags: Addr_Set{null}, Inverse{null}
* pageRequest.weblogAnchor: Addr_Set{null}, Inverse{null}
* pageRequest.weblogCategoryName: Addr_Set{null}, Inverse{null}
* pageRequest.weblogDate: Addr_Set{null}, Inverse{null}
* pageRequest.weblogPageName: Addr_Set{null}, Inverse{null}
* java.lang.String:equals(...)@204: {0}, {1}
* java.util.List:size(...)@206: {-231..0}, {1..232-1}
* java.util.Map:size(...)@229: {-231..0}, {1..232-1}
*/
166 StringBuffer key = new StringBuffer();
167
168 key.append(this.CACHE_ID).append(":");
169 key.append(pageRequest.getWeblogHandle());
170
171 if(pageRequest.getWeblogAnchor() != null) {
172
173 String anchor = null;
174 try {
175 // may contain spaces or other bad chars
176 anchor = URLEncoder.encode(pageRequest.getWeblogAnchor(), "UTF-8");
177 } catch(UnsupportedEncodingException ex) {
178 // ignored
179 }
180
181 key.append("/entry/").append(anchor);
182 } else {
183
184 if(pageRequest.getWeblogPageName() != null) {
185 key.append("/page/").append(pageRequest.getWeblogPageName());
186 }
187
188 if(pageRequest.getWeblogDate() != null) {
189 key.append("/").append(pageRequest.getWeblogDate());
190 }
191
192 if(pageRequest.getWeblogCategoryName() != null) {
193 String cat = null;
194 try {
195 // may contain spaces or other bad chars
196 cat = URLEncoder.encode(pageRequest.getWeblogCategoryName(), "UTF-8");
197 } catch(UnsupportedEncodingException ex) {
198 // ignored
199 }
200
201 key.append("/").append(cat);
202 }
203
204 if("tags".equals(pageRequest.getContext())) {
205 key.append("/tags/");
206 if(pageRequest.getTags() != null && pageRequest.getTags().size() > 0) {
207 Set ordered = new TreeSet(pageRequest.getTags());
208 String[] tags = (String[]) ordered.toArray(new String[ordered.size()]);
209 key.append(Utilities.stringArrayToString(tags,"+"));
210 }
211 }
212 }
213
214 if(pageRequest.getLocale() != null) {
215 key.append("/").append(pageRequest.getLocale());
216 }
217
218 // add page number when applicable
219 if(pageRequest.getWeblogAnchor() == null) {
220 key.append("/page=").append(pageRequest.getPageNum());
221 }
222
223 // add login state
224 if(pageRequest.getAuthenticUser() != null) {
225 key.append("/user=").append(pageRequest.getAuthenticUser());
226 }
227
228 // we allow for arbitrary query params for custom pages
229 if(pageRequest.getWeblogPageName() != null &&
230 pageRequest.getCustomParams().size() > 0) {
231 String queryString = paramsToString(pageRequest.getCustomParams());
232
233 key.append("/qp=").append(queryString);
234 }
235
236 return key.toString();
237 }
238
239
240 private String paramsToString(Map map) {
241
/*
P/P * Method: String paramsToString(Map)
*
* Presumptions:
* java.util.Map:keySet(...)@250 != null
* value.length@253 >= 1
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* map: Inverse{null}, Addr_Set{null}
* java.util.Iterator:hasNext(...)@251: {0}, {1}
* java.util.Map:get(...)@253: Addr_Set{null}, Inverse{null}
*/
242 if(map == null) {
243 return null;
244 }
245
246 StringBuffer string = new StringBuffer();
247
248 String key = null;
249 String[] value = null;
250 Iterator keys = map.keySet().iterator();
251 while(keys.hasNext()) {
252 key = (String) keys.next();
253 value = (String[]) map.get(key);
254
255 if(value != null) {
256 string.append(",").append(key).append("=").append(value[0]);
257 }
258 }
259
260 return Utilities.toBase64(string.toString().substring(1).getBytes());
261 }
262
263 }
SofCheck Inspector Build Version : 2.18479
| WeblogPageCache.java |
2009-Jan-02 14:25:42 |
| WeblogPageCache.class |
2009-Sep-04 03:12:45 |