KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > portal > coplet > adapter > impl > CachingURICopletAdapter


1 /*
2  * Copyright 1999-2002,2004-2005 The Apache Software Foundation.
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 package org.apache.cocoon.portal.coplet.adapter.impl;
17
18 import java.io.UnsupportedEncodingException JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23
24 import org.apache.avalon.framework.parameters.Parameterizable;
25 import org.apache.avalon.framework.parameters.Parameters;
26 import org.apache.avalon.framework.service.ServiceException;
27 import org.apache.avalon.framework.service.ServiceManager;
28 import org.apache.cocoon.ProcessingException;
29 import org.apache.cocoon.caching.Cache;
30 import org.apache.cocoon.caching.CachedResponse;
31 import org.apache.cocoon.components.sax.XMLByteStreamCompiler;
32 import org.apache.cocoon.components.sax.XMLByteStreamInterpreter;
33 import org.apache.cocoon.portal.PortalService;
34 import org.apache.cocoon.portal.coplet.CopletInstanceData;
35 import org.apache.cocoon.portal.event.CopletInstanceEvent;
36 import org.apache.cocoon.portal.event.impl.ChangeCopletInstanceAspectDataEvent;
37 import org.apache.cocoon.util.Deprecation;
38 import org.apache.cocoon.util.NetUtils;
39 import org.apache.excalibur.source.SourceValidity;
40 import org.xml.sax.ContentHandler JavaDoc;
41 import org.xml.sax.SAXException JavaDoc;
42 import org.xml.sax.ext.LexicalHandler JavaDoc;
43
44 /**
45  * This adapter extends the {@link org.apache.cocoon.portal.coplet.adapter.impl.URICopletAdapter}
46  * by a caching mechanism. The result of the called uri/pipeline is cached until a
47  * {@link org.apache.cocoon.portal.event.CopletInstanceEvent} for that coplet instance
48  * is received.
49  * The content can eiter be cached in the user session or globally. The default is
50  * the user session.
51  *
52  * @author <a HREF="mailto:gerald.kahrer@rizit.at">Gerald Kahrer</a>
53  * @author <a HREF="mailto:cziegeler.at.apache.dot.org">Carsten Ziegeler</a>
54  * @version $Id: CachingURICopletAdapter.java 291593 2005-09-26 10:49:55Z cziegeler $
55  */

56 public class CachingURICopletAdapter
57     extends URICopletAdapter
58     implements Parameterizable {
59
60     /** The configuration name for enabling/disabling the cache. */
61     public static final String JavaDoc CONFIGURATION_ENABLE_CACHING = "cache-enabled";
62
63     /** The configuration name for using the global cache. */
64     public static final String JavaDoc CONFIGURATION_CACHE_GLOBAL= "cache-global";
65
66     /** The configuration name for querying instance attributes to generate the key
67      * for the global cache. */

68     public static final String JavaDoc CONFIGURATION_CACHE_GLOBAL_USE_ATTRIBUTES= "cache-global-use-attributes";
69
70     /** The configuration name for ignoring sizing events to clear the cache. */
71     public static final String JavaDoc CONFIGURATION_IGNORE_SIZING_EVENTS = "ignore-sizing-events";
72
73     /** The temporary attribute name for the storing the cached coplet content. */
74     public static final String JavaDoc CACHE = "cacheData";
75
76     /** This temporary attribute can be set on the instance to not cache the current response. */
77     public static final String JavaDoc DO_NOT_CACHE = "doNotCache";
78
79     /**
80      * Caching can be basically disabled with this boolean parameter.
81      * @deprecated Use coplet base data configuration.
82      */

83     public static final String JavaDoc PARAMETER_DISABLE_CACHING = "disable_caching";
84
85     /** Is caching enabled? */
86     protected Boolean JavaDoc enableCaching = Boolean.TRUE;
87
88     /** The cache to use for global caching. */
89     protected Cache cache;
90
91     /**
92      * @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(org.apache.avalon.framework.parameters.Parameters)
93      */

94     public void parameterize(Parameters parameters) {
95         if ( parameters.getParameter(PARAMETER_DISABLE_CACHING, null) != null ) {
96             Deprecation.logger.info("The 'disable_caching' parameter on the caching uri coplet adapter is deprecated. "
97                                    +"Use the configuration of the base coplet data instead.");
98         }
99         boolean disableCaching = parameters.getParameterAsBoolean(PARAMETER_DISABLE_CACHING,
100                                                                   !this.enableCaching.booleanValue());
101         this.enableCaching = new Boolean JavaDoc(!disableCaching);
102         if ( this.getLogger().isInfoEnabled() ) {
103             this.getLogger().info(this.getClass().getName() + ": enable-caching=" + this.enableCaching);
104         }
105     }
106
107     /**
108      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
109      */

110     public void service(ServiceManager manager) throws ServiceException {
111         super.service(manager);
112         this.cache = (Cache)this.manager.lookup(Cache.ROLE);
113     }
114
115     /**
116      * @see org.apache.avalon.framework.activity.Disposable#dispose()
117      */

118     public void dispose() {
119         if ( this.manager != null ) {
120             this.manager.release(this.cache);
121             this.cache = null;
122         }
123         super.dispose();
124     }
125
126     /**
127      * @see org.apache.cocoon.portal.coplet.adapter.impl.AbstractCopletAdapter#streamContent(org.apache.cocoon.portal.coplet.CopletInstanceData, org.xml.sax.ContentHandler)
128      */

129     public void streamContent(CopletInstanceData coplet, ContentHandler JavaDoc contentHandler)
130     throws SAXException JavaDoc {
131         this.streamContent( coplet,
132                             (String JavaDoc) coplet.getCopletData().getAttribute("uri"),
133                             contentHandler);
134     }
135
136     /**
137      * @see org.apache.cocoon.portal.coplet.adapter.impl.URICopletAdapter#streamContent(org.apache.cocoon.portal.coplet.CopletInstanceData, java.lang.String, org.xml.sax.ContentHandler)
138      */

139     public void streamContent( final CopletInstanceData coplet,
140                                final String JavaDoc uri,
141                                final ContentHandler JavaDoc contentHandler)
142     throws SAXException JavaDoc {
143         // Is caching enabled?
144
boolean cachingEnabled = ((Boolean JavaDoc)this.getConfiguration(coplet, CONFIGURATION_ENABLE_CACHING, this.enableCaching)).booleanValue();
145         // do we cache globally?
146
boolean cacheGlobal = ((Boolean JavaDoc)this.getConfiguration(coplet, CONFIGURATION_CACHE_GLOBAL, Boolean.FALSE)).booleanValue();
147
148         Object JavaDoc data = null;
149         // If caching is enabed and the cache is still valid, then use the cache
150
if (cachingEnabled) {
151             if ( cacheGlobal ) {
152                 final String JavaDoc key = this.getCacheKey(coplet, uri);
153                 CachedResponse response = this.cache.get(key);
154                 if (response != null ) {
155                     data = response.getResponse();
156                 }
157             } else {
158                 data = coplet.getTemporaryAttribute(CACHE);
159             }
160         }
161         if (data == null) {
162             // if caching is permanently or temporary disabled, flush the cache and invoke coplet
163
if ( !cachingEnabled || coplet.getTemporaryAttribute(DO_NOT_CACHE) != null ) {
164                 coplet.removeTemporaryAttribute(DO_NOT_CACHE);
165                 if ( cacheGlobal ) {
166                     final String JavaDoc key = this.getCacheKey(coplet, uri);
167                     this.cache.remove(key);
168                 } else {
169                     coplet.removeTemporaryAttribute(CACHE);
170                 }
171                 super.streamContent(coplet, uri, contentHandler);
172             } else {
173
174                 XMLByteStreamCompiler bc = new XMLByteStreamCompiler();
175
176                 super.streamContent(coplet, uri, bc);
177                 data = bc.getSAXFragment();
178                 if (coplet.removeTemporaryAttribute(DO_NOT_CACHE) == null) {
179                     if ( cacheGlobal ) {
180                         CachedResponse response = new CachedResponse((SourceValidity[])null, (byte[])data);
181                         try {
182                             final String JavaDoc key = this.getCacheKey(coplet, uri);
183                             this.cache.store(key, response);
184                         } catch (ProcessingException pe) {
185                             // we ignore this
186
this.getLogger().warn("Exception during storing response into cache.", pe);
187                         }
188                     } else {
189                         coplet.setTemporaryAttribute(CACHE, data);
190                     }
191                 }
192             }
193         }
194         // and now stream the data
195
if ( data != null ) {
196             XMLByteStreamInterpreter bi = new XMLByteStreamInterpreter();
197             bi.setContentHandler(contentHandler);
198             if ( contentHandler instanceof LexicalHandler JavaDoc ) {
199                 bi.setLexicalHandler((LexicalHandler JavaDoc)contentHandler);
200             }
201             bi.deserialize(data);
202         }
203     }
204
205     /**
206      * @see org.apache.cocoon.portal.event.Receiver
207      */

208     public void inform(CopletInstanceEvent e, PortalService service) {
209         if ( this.getLogger().isInfoEnabled() ) {
210             this.getLogger().info("CopletInstanceEvent " + e + " caught by CachingURICopletAdapter");
211         }
212         this.handleCopletInstanceEvent(e);
213         super.inform(e, service);
214     }
215
216     /**
217      * This adapter listens for CopletInstanceEvents. Each event sets the cache invalid.
218      */

219     public void handleCopletInstanceEvent(CopletInstanceEvent event) {
220         final CopletInstanceData coplet = (CopletInstanceData) event.getTarget();
221
222         // do we ignore SizingEvents
223
boolean ignoreSizing = ((Boolean JavaDoc)this.getConfiguration(coplet, CONFIGURATION_IGNORE_SIZING_EVENTS, Boolean.TRUE)).booleanValue();
224
225         if ( !ignoreSizing || !isSizingEvent(event)) {
226             // do we cache globally?
227
boolean cacheGlobal = ((Boolean JavaDoc)this.getConfiguration(coplet, CONFIGURATION_CACHE_GLOBAL, Boolean.FALSE)).booleanValue();
228             if ( cacheGlobal ) {
229                 final String JavaDoc key = this.getCacheKey(coplet,
230                                                     (String JavaDoc) coplet.getCopletData().getAttribute("uri"));
231                 this.cache.remove(key);
232             } else {
233                 coplet.removeTemporaryAttribute(CACHE);
234             }
235         }
236     }
237
238     /**
239      * Tests if the event is a sizing event for the coplet.
240      */

241     protected boolean isSizingEvent(CopletInstanceEvent event) {
242         if ( event instanceof ChangeCopletInstanceAspectDataEvent ) {
243             if (((ChangeCopletInstanceAspectDataEvent)event).getAspectName().equals("size")) {
244                 return true;
245             }
246         }
247         return false;
248     }
249
250     /**
251      * Build the key for the global cache.
252      */

253     protected String JavaDoc getCacheKey(CopletInstanceData coplet, String JavaDoc uri) {
254         final Boolean JavaDoc useAttributes = (Boolean JavaDoc)this.getConfiguration(coplet,
255                                                             CONFIGURATION_CACHE_GLOBAL_USE_ATTRIBUTES,
256                                                             Boolean.FALSE);
257         if ( !useAttributes.booleanValue() ) {
258             return "coplet:" + coplet.getCopletData().getId() + '/' + uri;
259         }
260         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("coplet:");
261         buffer.append(coplet.getCopletData().getId());
262         buffer.append('/');
263         buffer.append(uri);
264         boolean hasParams = false;
265         // first add attributes:
266
// sort the keys
267
List JavaDoc keyList = new ArrayList JavaDoc(coplet.getAttributes().keySet());
268         Collections.sort(keyList);
269         Iterator JavaDoc i = keyList.iterator();
270         while ( i.hasNext() ) {
271             final Object JavaDoc name = i.next();
272             final Object JavaDoc value = coplet.getAttribute(name.toString());
273             if ( hasParams ) {
274                 buffer.append('&');
275             } else {
276                 buffer.append('?');
277                 hasParams = true;
278             }
279             buffer.append(name.toString());
280             buffer.append('=');
281             if ( value != null ) {
282                 try {
283                     buffer.append(NetUtils.encode(value.toString(), "utf-8"));
284                 } catch (UnsupportedEncodingException JavaDoc ignore) {
285                     // we ignore this
286
}
287             }
288         }
289         // second add temporary attributes
290
keyList = new ArrayList JavaDoc(coplet.getTemporaryAttributes().keySet());
291         Collections.sort(keyList);
292         i = keyList.iterator();
293         while ( i.hasNext() ) {
294             final Object JavaDoc name = i.next();
295             final Object JavaDoc value = coplet.getTemporaryAttribute(name.toString());
296             if ( hasParams ) {
297                 buffer.append('&');
298             } else {
299                 buffer.append('?');
300                 hasParams = true;
301             }
302             buffer.append(name.toString());
303             buffer.append('=');
304             if ( value != null ) {
305                 try {
306                     buffer.append(NetUtils.encode(value.toString(), "utf-8"));
307                 } catch (UnsupportedEncodingException JavaDoc ignore) {
308                     // we ignore this
309
}
310             }
311         }
312         return buffer.toString();
313     }
314 }
315
Popular Tags