KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jasperreports > engine > fill > JRAbstractLRUVirtualizer


1 /*
2  * ============================================================================
3  * GNU Lesser General Public License
4  * ============================================================================
5  *
6  * JasperReports - Free Java report-generating library.
7  * Copyright (C) 2005 Works, Inc. http://www.works.com/
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * Works, Inc.
24  * 6034 West Courtyard Drive
25  * Suite 210
26  * Austin, TX 78730-5032
27  * USA
28  * http://www.works.com/
29  */

30
31 /*
32  * Licensed to JasperSoft Corporation under a Contributer Agreement
33  */

34 package net.sf.jasperreports.engine.fill;
35
36 import java.io.IOException JavaDoc;
37 import java.io.InputStream JavaDoc;
38 import java.io.ObjectInputStream JavaDoc;
39 import java.io.ObjectOutputStream JavaDoc;
40 import java.io.OutputStream JavaDoc;
41 import java.lang.ref.Reference JavaDoc;
42 import java.lang.ref.ReferenceQueue JavaDoc;
43 import java.lang.ref.WeakReference JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.Map JavaDoc;
46 import java.util.Map.Entry;
47
48 import net.sf.jasperreports.engine.JRConstants;
49 import net.sf.jasperreports.engine.JRRuntimeException;
50 import net.sf.jasperreports.engine.JRVirtualizable;
51 import net.sf.jasperreports.engine.JRVirtualizer;
52
53 import org.apache.commons.collections.LRUMap;
54 import org.apache.commons.collections.ReferenceMap;
55 import org.apache.commons.logging.Log;
56 import org.apache.commons.logging.LogFactory;
57
58
59 /**
60  * Abstract base for LRU and serialization based virtualizer
61  *
62  * @author John Bindel
63  * @version $Id: JRAbstractLRUVirtualizer.java 1333 2006-07-11 14:31:34 +0300 (Tue, 11 Jul 2006) lucianc $
64  */

65 public abstract class JRAbstractLRUVirtualizer implements JRVirtualizer
66 {
67     private static final Log log = LogFactory.getLog(JRAbstractLRUVirtualizer.class);
68
69     protected static class CacheReference extends WeakReference JavaDoc
70     {
71         private final String JavaDoc id;
72
73         public CacheReference(JRVirtualizable o, ReferenceQueue JavaDoc queue)
74         {
75             super(o, queue);
76             id = o.getUID();
77         }
78         
79         public String JavaDoc getId()
80         {
81             return id;
82         }
83     }
84     
85     /**
86      * This class keeps track of how many objects are currently in memory, and
87      * when there are too many, it pushes the last touched one to disk.
88      */

89     protected class Cache
90     {
91         protected class LRUScanMap extends LRUMap
92         {
93             private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
94             
95             public LRUScanMap(int maxSize)
96             {
97                 super(maxSize);
98             }
99
100             protected void removeLRU()
101             {
102                 Map.Entry JavaDoc entry = getFirst();
103                 boolean found = isRemovable(entry);
104                 if (!found)
105                 {
106                     Iterator JavaDoc entriesIt = entrySet().iterator();
107                     entriesIt.next(); //skipping the first, which is already checked
108
while(!found && entriesIt.hasNext())
109                     {
110                         entry = (Entry) entriesIt.next();
111                         found = isRemovable(entry);
112                     }
113                 }
114
115                 if (!found)
116                 {
117                     throw new JRRuntimeException("The virtualizer is used by more contexts than its in-memory cache size " + getMaximumSize());
118                 }
119
120                 Object JavaDoc key = entry.getKey();
121                 Object JavaDoc value = entry.getValue();
122                 this.remove(key);
123                 processRemovedLRU(key,value);
124             }
125
126             protected boolean isRemovable(Map.Entry JavaDoc entry)
127             {
128                 JRVirtualizable value = getMapValue(entry.getValue());
129                 return value == null || !lastObjectSet.containsKey(value);
130             }
131
132             protected void processRemovedLRU(Object JavaDoc key, Object JavaDoc value)
133             {
134                 JRVirtualizable o = getMapValue(value);
135                 if (o != null)
136                 {
137                     virtualizeData(o);
138                 }
139             }
140         }
141         
142         private final ReferenceQueue JavaDoc refQueue;
143         private final LRUScanMap map;
144
145         Cache(int maxSize)
146         {
147             map = new LRUScanMap(maxSize);
148             refQueue = new ReferenceQueue JavaDoc();
149         }
150         
151         protected JRVirtualizable getMapValue(Object JavaDoc val)
152         {
153             JRVirtualizable o;
154             if (val == null)
155             {
156                 o = null;
157             }
158             else
159             {
160                 Reference JavaDoc ref = (Reference JavaDoc) val;
161                 if (ref.isEnqueued())
162                 {
163                     o = null;
164                 }
165                 else
166                 {
167                     o = (JRVirtualizable) ref.get();
168                 }
169             }
170             return o;
171         }
172         
173         protected Object JavaDoc toMapValue(JRVirtualizable val)
174         {
175             return val == null ? null : new CacheReference(val, refQueue);
176         }
177         
178         protected void purge()
179         {
180             CacheReference ref;
181             while ((ref = (CacheReference) refQueue.poll()) != null)
182             {
183                 map.remove(ref.getId());
184             }
185         }
186
187         public JRVirtualizable get(String JavaDoc id)
188         {
189             purge();
190             
191             return getMapValue(map.get(id));
192         }
193
194         public JRVirtualizable put(String JavaDoc id, JRVirtualizable o)
195         {
196             purge();
197             
198             return getMapValue(map.put(id, toMapValue(o)));
199         }
200
201         public JRVirtualizable remove(String JavaDoc id)
202         {
203             purge();
204             
205             return getMapValue(map.remove(id));
206         }
207         
208         public Iterator JavaDoc idIterator()
209         {
210             purge();
211             
212             final Iterator JavaDoc valsIt = map.values().iterator();
213             return new Iterator JavaDoc()
214             {
215                 public boolean hasNext()
216                 {
217                     return valsIt.hasNext();
218                 }
219
220                 public Object JavaDoc next()
221                 {
222                     CacheReference ref = (CacheReference) valsIt.next();
223                     return ref.getId();
224                 }
225
226                 public void remove()
227                 {
228                     valsIt.remove();
229                 }
230             };
231         }
232     }
233
234     private final Cache pagedIn;
235
236     private final ReferenceMap pagedOut;
237
238     protected JRVirtualizable lastObject;
239     protected ReferenceMap lastObjectMap;
240     protected ReferenceMap lastObjectSet;
241
242     private boolean readOnly;
243
244     /**
245      * @param maxSize
246      * the maximum size (in JRVirtualizable objects) of the paged in
247      * cache.
248      */

249     protected JRAbstractLRUVirtualizer(int maxSize)
250     {
251         this.pagedIn = new Cache(maxSize);
252         this.pagedOut = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
253         this.lastObject = null;
254         
255         this.lastObjectMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
256         this.lastObjectSet = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD);
257     }
258
259     protected synchronized final boolean isPagedOut(String JavaDoc id)
260     {
261         return pagedOut.containsKey(id);
262     }
263
264     protected synchronized boolean isPagedOutAndTouch(JRVirtualizable o, String JavaDoc uid)
265     {
266         boolean virtualized = isPagedOut(uid);
267         if (!virtualized)
268         {
269             touch(o);
270         }
271         return virtualized;
272     }
273     
274     protected final void setLastObject(JRVirtualizable o)
275     {
276         if (lastObject != o)
277         {
278             if (o != null)
279             {
280                 JRVirtualizationContext context = o.getContext();
281                 Object JavaDoc ownerLast = lastObjectMap.get(context);
282                 if (ownerLast != o)
283                 {
284                     if (ownerLast != null)
285                     {
286                         lastObjectSet.remove(ownerLast);
287                     }
288                     lastObjectMap.put(context, o);
289                     lastObjectSet.put(o, Boolean.TRUE);
290                 }
291             }
292             this.lastObject = o;
293         }
294     }
295
296     /**
297      * Sets the read only mode for the virtualizer.
298      * <p/>
299      * When in read-only mode, the virtualizer assumes that virtualizable objects are final
300      * and any change in a virtualizable object's data is discarded.
301      * <p/>
302      * When the virtualizer is used for multiple virtualization contexts (in shared mode),
303      * calling this method would override the read-only flags from all the contexts and all the
304      * objects will be manipulated in read-only mode.
305      * Use {@link JRVirtualizationContext#setReadOnly(boolean) JRVirtualizationContext.setReadOnly(boolean)}
306      * to set the read-only mode for one specific context.
307      *
308      * @param ro the read-only mode to set
309      */

310     public void setReadOnly(boolean ro)
311     {
312         this.readOnly = ro;
313     }
314
315     
316     /**
317      * Determines whether the virtualizer is in read-only mode.
318      *
319      * @return whether the virtualizer is in read-only mode
320      * @see #setReadOnly(boolean)
321      */

322     public boolean isReadOnly()
323     {
324         return readOnly;
325     }
326
327     protected final boolean isReadOnly(JRVirtualizable o)
328     {
329         return readOnly || o.getContext().isReadOnly();
330     }
331
332     public synchronized void registerObject(JRVirtualizable o)
333     {
334         setLastObject(o);
335         JRVirtualizable old = pagedIn.put(o.getUID(), o);
336         if (old != null)
337         {
338             pagedIn.put(o.getUID(), old);
339             throw new IllegalStateException JavaDoc("Wrong object stored with UID \"" + o.getUID() + "\"");
340         }
341     }
342
343     public void deregisterObject(JRVirtualizable o)
344     {
345         String JavaDoc uid = o.getUID();
346
347         //try to remove virtual data
348
try
349         {
350             dispose(o.getUID());
351         }
352         catch (Exception JavaDoc e)
353         {
354             log.error("Error removing virtual data", e);
355             //ignore
356
}
357
358         synchronized(this)
359         {
360             JRVirtualizable oldIn = pagedIn.remove(uid);
361             if (oldIn != null)
362             {
363                 if (oldIn != o)
364                 {
365                     pagedIn.put(uid, oldIn);
366                     throw new IllegalStateException JavaDoc("Wrong object stored with UID \"" + o.getUID() + "\"");
367                 }
368             }
369             else
370             {
371                 Object JavaDoc oldOut = pagedOut.remove(uid);
372                 if (oldOut != null && oldOut != o)
373                 {
374                     pagedOut.put(uid, oldOut);
375                     throw new IllegalStateException JavaDoc("Wrong object stored with UID \"" + o.getUID() + "\"");
376                 }
377             }
378
379             // We don't really care if someone deregisters an object
380
// that's not registered.
381
}
382     }
383
384     public synchronized void touch(JRVirtualizable o)
385     {
386         // If we just touched this object, don't touch it again.
387
if (this.lastObject != o)
388         {
389             setLastObject(pagedIn.get(o.getUID()));
390         }
391     }
392     
393     public void requestData(JRVirtualizable o)
394     {
395         String JavaDoc uid = o.getUID();
396         if (isPagedOutAndTouch(o, uid))
397         {
398             // unvirtualize
399
try
400             {
401                 pageIn(o);
402             }
403             catch (IOException JavaDoc e)
404             {
405                 log.error("Error devirtualizing object", e);
406                 throw new JRRuntimeException(e);
407             }
408
409             o.afterInternalization();
410
411             synchronized (this)
412             {
413                 setLastObject(o);
414                 pagedOut.remove(uid);
415                 pagedIn.put(uid, o);
416             }
417         }
418     }
419
420     public void clearData(JRVirtualizable o)
421     {
422         String JavaDoc uid = o.getUID();
423         if (isPagedOutAndTouch(o, uid))
424         {
425             // remove virtual data
426
dispose(uid);
427             
428             synchronized (this)
429             {
430                 pagedOut.remove(uid);
431             }
432         }
433     }
434
435     public void virtualizeData(JRVirtualizable o)
436     {
437         String JavaDoc uid = o.getUID();
438         if (!isPagedOut(uid))
439         {
440             o.beforeExternalization();
441
442             // virtualize
443
try
444             {
445                 pageOut(o);
446             }
447             catch (IOException JavaDoc e)
448             {
449                 log.error("Error virtualizing object", e);
450                 throw new JRRuntimeException(e);
451             }
452             
453             o.afterExternalization();
454
455             // Wait until we know it worked before tossing the data.
456
o.removeVirtualData();
457
458             synchronized (this)
459             {
460                 pagedOut.put(uid, o);
461             }
462         }
463     }
464
465     protected void finalize() throws Throwable JavaDoc
466     {
467         cleanup();
468
469         super.finalize();
470     }
471
472     /**
473      * Writes serialized indentity and virtual data of a virtualizable object to a stream.
474      *
475      * @param o the serialized object
476      * @param out the output stream
477      * @throws JRRuntimeException
478      */

479     protected final void writeData(JRVirtualizable o, OutputStream JavaDoc out)
480             throws JRRuntimeException
481     {
482         try
483         {
484             ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(out);
485             oos.writeObject(o.getIdentityData());
486             oos.writeObject(o.getVirtualData());
487             oos.flush();
488         }
489         catch (IOException JavaDoc e)
490         {
491             log.error("Error virtualizing object", e);
492             throw new JRRuntimeException(e);
493         }
494     }
495
496     
497     /**
498      * Reads serialized identity and virtual data for a virtualizable object
499      * from a stream.
500      *
501      * @param o the virtualizable object
502      * @param in the input stream
503      * @throws JRRuntimeException
504      */

505     protected final void readData(JRVirtualizable o, InputStream JavaDoc in)
506             throws JRRuntimeException
507     {
508         try
509         {
510             ObjectInputStream JavaDoc ois = new ObjectInputStream JavaDoc(in);
511             o.setIdentityData(ois.readObject());
512             o.setVirtualData(ois.readObject());
513         }
514         catch (IOException JavaDoc e)
515         {
516             log.error("Error devirtualizing object", e);
517             throw new JRRuntimeException(e);
518         }
519         catch (ClassNotFoundException JavaDoc e)
520         {
521             log.error("Error devirtualizing object", e);
522             throw new JRRuntimeException(e);
523         }
524     }
525
526     protected synchronized void reset()
527     {
528         readOnly = false;
529     }
530
531     protected final void disposeAll()
532     {
533         // Remove all paged-out swap files.
534
for (Iterator JavaDoc it = pagedOut.keySet().iterator(); it.hasNext();)
535         {
536             String JavaDoc id = (String JavaDoc) it.next();
537             try
538             {
539                 dispose(id);
540                 it.remove();
541             }
542             catch (Exception JavaDoc e)
543             {
544                 log.error("Error cleaning up virtualizer.", e);
545                 // Do nothing because we want to try to remove all swap files.
546
}
547         }
548
549         for (Iterator JavaDoc it = pagedIn.idIterator(); it.hasNext();)
550         {
551             String JavaDoc id = (String JavaDoc) it.next();
552             try
553             {
554                 dispose(id);
555                 it.remove();
556             }
557             catch (Exception JavaDoc e)
558             {
559                 log.error("Error cleaning up virtualizer.", e);
560                 // Do nothing because we want to try to remove all swap files.
561
}
562         }
563     }
564
565     /**
566      * Writes a virtualizable object's data to an external storage.
567      *
568      * @param o a virtualizable object
569      * @throws IOException
570      */

571     protected abstract void pageOut(JRVirtualizable o) throws IOException JavaDoc;
572     
573
574     /**
575      * Reads a virtualizable object's data from an external storage.
576      *
577      * @param o a virtualizable object
578      * @throws IOException
579      */

580     protected abstract void pageIn(JRVirtualizable o) throws IOException JavaDoc;
581     
582     
583     /**
584      * Removes the external data associated with a virtualizable object.
585      *
586      * @param virtualId the ID of the virtualizable object
587      */

588     protected abstract void dispose(String JavaDoc virtualId);
589 }
590
Popular Tags