KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jasperreports > engine > base > JRVirtualPrintPage


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.base;
35
36 import java.awt.Graphics2D JavaDoc;
37 import java.awt.geom.Dimension2D JavaDoc;
38 import java.awt.geom.Rectangle2D JavaDoc;
39 import java.io.ByteArrayInputStream JavaDoc;
40 import java.io.ByteArrayOutputStream JavaDoc;
41 import java.io.IOException JavaDoc;
42 import java.io.ObjectInputStream JavaDoc;
43 import java.io.ObjectOutputStream JavaDoc;
44 import java.io.Serializable JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.HashSet JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.List JavaDoc;
50 import java.util.Map JavaDoc;
51 import java.util.Random JavaDoc;
52 import java.util.Set JavaDoc;
53
54 import org.apache.commons.logging.Log;
55 import org.apache.commons.logging.LogFactory;
56
57 import net.sf.jasperreports.engine.JRConstants;
58 import net.sf.jasperreports.engine.JRException;
59 import net.sf.jasperreports.engine.JRPrintElement;
60 import net.sf.jasperreports.engine.JRPrintFrame;
61 import net.sf.jasperreports.engine.JRPrintImage;
62 import net.sf.jasperreports.engine.JRPrintPage;
63 import net.sf.jasperreports.engine.JRRenderable;
64 import net.sf.jasperreports.engine.JRRuntimeException;
65 import net.sf.jasperreports.engine.JRVirtualizable;
66 import net.sf.jasperreports.engine.JRVirtualizationHelper;
67 import net.sf.jasperreports.engine.JRVirtualizer;
68 import net.sf.jasperreports.engine.JasperPrint;
69 import net.sf.jasperreports.engine.fill.JRTemplateElement;
70 import net.sf.jasperreports.engine.fill.JRTemplatePrintElement;
71 import net.sf.jasperreports.engine.fill.JRVirtualizationContext;
72
73 /**
74  * A print page that can be virtualized to free heap memory.
75  *
76  * @author John Bindel
77  * @version $Id: JRVirtualPrintPage.java 1333 2006-07-11 14:31:34 +0300 (Tue, 11 Jul 2006) lucianc $
78  */

79 public class JRVirtualPrintPage implements JRPrintPage, JRVirtualizable, Serializable JavaDoc
80 {
81     protected static final Log log = LogFactory.getLog(JRVirtualPrintPage.class);
82     
83     /**
84      * Identity objects are those that we want to replace when we devirtualize
85      * data. If object A was virtualized, and it is referenced outside the
86      * virtualized data, then we want to replace those references with object
87      * A', which is the version of the object that has been devirtualized. For
88      * example the Serialization mechanism creates a new version of the
89      * TextElement we want to be filled, but the bound object map references the
90      * original object A until we replace it with the new version A'.
91      */

92     public static class ObjectIDPair implements Serializable JavaDoc {
93         /**
94          *
95          */

96         private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
97
98         private final Object JavaDoc o;
99
100         private final int id;
101
102         public ObjectIDPair(Object JavaDoc o) {
103             this.o = o;
104             this.id = System.identityHashCode(o);
105         }
106
107         /**
108          * Gets the object.
109          */

110         public Object JavaDoc getObject() {
111             return o;
112         }
113
114         /**
115          * Gets the identity of the object. The identity is the current object's
116          * identity hash code before we deserialize, but when we have
117          * deserialized it, the identity is that of the object that was
118          * serialized, not that of the newly deserialized object.
119          */

120         public int getIdentity() {
121             return id;
122         }
123     }
124
125     /**
126      * Classes that want to deal with the identity data should implement this.
127      * The JRBaseFiller needs to do this.
128      */

129     public static interface IdentityDataProvider {
130         /**
131          * Get identity data that the provider later want to handle when the
132          * virtual object is paged in.
133          */

134         ObjectIDPair[] getIdentityData(JRVirtualPrintPage page);
135
136         /**
137          * Handle the identity data as necessary.
138          */

139         void setIdentityData(JRVirtualPrintPage page,
140                 ObjectIDPair[] identityData);
141     }
142
143     private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
144
145     private static final Random JavaDoc random = new Random JavaDoc(System.currentTimeMillis());
146
147     private static short counter = 1;
148     
149     
150     protected List JavaDoc elements = new ArrayList JavaDoc();
151
152     /**
153      * A unique identifier that is useful for serialization and deserialization
154      * to some persistence mechanism.
155      */

156     private String JavaDoc uid;
157
158     /**
159      * The object that does the virtualization work.
160      */

161     private transient JRVirtualizer virtualizer;
162
163     /**
164      * The filler object which has our identity data.
165      */

166     private transient IdentityDataProvider[] identityProviders;
167
168     protected JRVirtualizationContext virtualizationContext;
169     
170     /**
171      * Constructs a virtualizable page.
172      */

173     public JRVirtualPrintPage(JasperPrint printObject, JRVirtualizer virtualizer, JRVirtualizationContext virtualizationContext) {
174         super();
175         
176         this.virtualizationContext = virtualizationContext;
177
178         this.uid = makeUID(printObject);
179         this.virtualizer = virtualizer;
180         this.identityProviders = null;
181         if (virtualizer != null) {
182             virtualizer.registerObject(this);
183         }
184     }
185     
186     
187     /**
188      * Make some unique identifier for this object.
189      */

190     private static String JavaDoc makeUID(JasperPrint printObject) {
191         synchronized (random) {
192             return Integer.toString(System.identityHashCode(printObject)) + "_"
193                     + (printObject.getPages().size()) + "_"
194                     + Integer.toString(counter++) + "_"
195                     + Integer.toString(random.nextInt());
196         }
197     }
198
199     public final String JavaDoc getUID() {
200         return this.uid;
201     }
202
203     public void setVirtualData(Object JavaDoc o)
204     {
205         elements = (List JavaDoc) o;
206     }
207     
208     public Object JavaDoc getVirtualData()
209     {
210         return elements;
211     }
212
213     public void removeVirtualData() {
214         elements = null;
215     }
216
217     public void setIdentityData(Object JavaDoc o) {
218         if (identityProviders != null) {
219             for (int i = 0; i < identityProviders.length; ++i) {
220                 identityProviders[i].setIdentityData(this, (ObjectIDPair[]) o);
221             }
222         }
223     }
224
225     public Object JavaDoc getIdentityData() {
226         ObjectIDPair[] data;
227         if (identityProviders != null) {
228             if (identityProviders.length == 1) {
229                 data = identityProviders[0].getIdentityData(this);
230             } else if (identityProviders.length > 1) {
231                 Set JavaDoc list = new HashSet JavaDoc();
232                 for (int i = 0; i < identityProviders.length; ++i) {
233                     ObjectIDPair[] pairs = identityProviders[i]
234                             .getIdentityData(this);
235                     if (pairs != null) {
236                         for (int j = 0; j < pairs.length; ++j) {
237                             list.add(pairs[j]);
238                         }
239                     }
240                 }
241                 data = (ObjectIDPair[]) list.toArray(new ObjectIDPair[list
242                         .size()]);
243             } else {
244                 data = null;
245             }
246         } else {
247             data = null;
248         }
249
250         return data;
251     }
252
253     public boolean isVirtualized() {
254         return elements == null;
255     }
256
257     /**
258      * Sets the virtualizer.
259      */

260     public void setVirtualizer(JRVirtualizer virtualizer) {
261         this.virtualizer = virtualizer;
262     }
263
264     /**
265      * Gets the virtualizer.
266      */

267     public JRVirtualizer getVirtualizer() {
268         return this.virtualizer;
269     }
270
271     public void addIdentityDataProvider(IdentityDataProvider p) {
272         if (identityProviders == null) {
273             identityProviders = new IdentityDataProvider[] { p };
274         } else {
275             IdentityDataProvider[] newList = new IdentityDataProvider[identityProviders.length + 1];
276             System.arraycopy(identityProviders, 0, newList, 0,
277                     identityProviders.length);
278             newList[identityProviders.length] = p;
279             identityProviders = newList;
280         }
281     }
282
283     public void removeIdentityDataProvider(IdentityDataProvider p) {
284         if (identityProviders != null) {
285             int idx;
286             for (idx = 0; idx < identityProviders.length; ++idx) {
287                 if (identityProviders[idx] == p) {
288                     IdentityDataProvider[] newList = new IdentityDataProvider[identityProviders.length - 1];
289                     System.arraycopy(identityProviders, 0, newList, 0, idx);
290                     int remaining = identityProviders.length - idx - 1;
291                     if (remaining > 0) {
292                         System.arraycopy(identityProviders, idx + 1, newList,
293                                 idx, remaining);
294                     }
295                     identityProviders = newList;
296                     break;
297                 }
298             }
299         }
300     }
301
302     public List JavaDoc getElements()
303     {
304         ensureVirtualData();
305         return elements;
306     }
307
308     protected void ensureVirtualData()
309     {
310         if (this.virtualizer != null)
311         {
312             this.virtualizer.requestData(this);
313         }
314     }
315
316     public void setElements(List JavaDoc elements) {
317         cleanVirtualData();
318         this.elements = elements;
319         cacheInContext(this.elements);
320     }
321
322     protected void cleanVirtualData()
323     {
324         if (this.virtualizer != null)
325         {
326             this.virtualizer.clearData(this);
327         }
328     }
329
330     
331     public void addElement(JRPrintElement element)
332     {
333         ensureVirtualData();
334         elements.add(element);
335         cacheInContext(element);
336     }
337     
338     
339     /**
340      * Dummy image renderer that only stores the ID of a cached renderer.
341      * When a page gets serialized, all image renderers that are cached in the
342      * virtualization context are replaced with dummy renderers that only store the ID.
343      * When a page gets deserialized, the original renderers are restored from the
344      * virtualization context based on the ID.
345      */

346     protected static class JRIdHolderRenderer implements JRRenderable, Serializable JavaDoc
347     {
348         private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
349         
350         protected final String JavaDoc id;
351         
352         protected JRIdHolderRenderer(JRRenderable renderer)
353         {
354             this.id = renderer.getId();
355         }
356
357         public String JavaDoc getId()
358         {
359             return id;
360         }
361
362         public byte getType()
363         {
364             return TYPE_IMAGE;
365         }
366
367         public byte getImageType()
368         {
369             return IMAGE_TYPE_UNKNOWN;
370         }
371
372         public Dimension2D JavaDoc getDimension() throws JRException
373         {
374             return null;
375         }
376
377         public byte[] getImageData() throws JRException
378         {
379             return null;
380         }
381
382         public void render(Graphics2D JavaDoc grx, Rectangle2D JavaDoc rectanle) throws JRException
383         {
384         }
385     }
386     
387     
388     protected static class JRIdHolderTemplateElement extends JRTemplateElement
389     {
390         private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
391         
392         protected JRIdHolderTemplateElement(String JavaDoc id)
393         {
394             super(id);
395         }
396     }
397     
398     private void readObject(java.io.ObjectInputStream JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc
399     {
400         uid = (String JavaDoc) in.readObject();
401         virtualizationContext = (JRVirtualizationContext) in.readObject();
402         
403         int length = in.readInt();
404         byte[] buffer = new byte[length];
405         in.readFully(buffer);
406         ByteArrayInputStream JavaDoc inputStream = new ByteArrayInputStream JavaDoc(buffer, 0, buffer.length);
407         ObjectInputStream JavaDoc elementsStream = new ObjectInputStream JavaDoc(inputStream);
408         elements = (List JavaDoc) elementsStream.readObject();
409         afterInternalization();
410         
411         setThreadVirtualizer();
412     }
413
414     
415     private void writeObject(java.io.ObjectOutputStream JavaDoc out) throws IOException JavaDoc
416     {
417         ensureVirtualData();
418         beforeExternalization();
419         
420         try
421         {
422             out.writeObject(uid);
423             out.writeObject(virtualizationContext);
424
425             ByteArrayOutputStream JavaDoc bout = new ByteArrayOutputStream JavaDoc();
426             ObjectOutputStream JavaDoc stream = new ObjectOutputStream JavaDoc(bout);
427             stream.writeObject(elements);
428             stream.flush();
429
430             byte[] bytes = bout.toByteArray();
431             out.writeInt(bytes.length);
432             out.write(bytes);
433         }
434         finally
435         {
436             afterExternalization();
437         }
438     }
439
440     
441     private void setThreadVirtualizer()
442     {
443         JRVirtualizer threadVirtualizer = JRVirtualizationHelper.getThreadVirtualizer();
444         if (threadVirtualizer != null)
445         {
446             virtualizer = threadVirtualizer;
447             virtualizer.registerObject(this);
448         }
449     }
450
451
452     protected void finalize()
453     {
454         if (virtualizer != null)
455         {
456             virtualizer.deregisterObject(this);
457         }
458     }
459     
460     
461     /**
462      * Returns all the elements on the page, including the ones placed inside
463      * {@link JRPrintFrame frames}.
464      *
465      * @return all the elements on the page
466      */

467     protected List JavaDoc getDeepElements()
468     {
469         List JavaDoc deepElements = new ArrayList JavaDoc(elements.size());
470         collectDeepElements(elements, deepElements);
471         return deepElements;
472     }
473
474     protected void collectDeepElements(List JavaDoc elementsList, List JavaDoc deepElements)
475     {
476         for (Iterator JavaDoc it = elementsList.iterator(); it.hasNext();)
477         {
478             JRPrintElement element = (JRPrintElement) it.next();
479             deepElements.add(element);
480             
481             if (element instanceof JRPrintFrame)
482             {
483                 JRPrintFrame frame = (JRPrintFrame) element;
484                 collectDeepElements(frame.getElements(), deepElements);
485             }
486         }
487     }
488
489
490     public void beforeExternalization()
491     {
492         setElementsExternalData();
493     }
494
495
496     protected void setElementsExternalData()
497     {
498         traverseDeepElements(new ExternalizationElementVisitor());
499     }
500
501
502     protected void setExternalizationRenderer(JRPrintImage image)
503     {
504         JRRenderable renderer = image.getRenderer();
505         if (renderer != null && virtualizationContext.hasCachedRenderer(renderer.getId()))
506         {
507             image.setRenderer(new JRIdHolderRenderer(renderer));
508         }
509     }
510
511
512     protected void cacheInContext(List JavaDoc elementList)
513     {
514         if (elementList != null && !elementList.isEmpty())
515         {
516             for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();)
517             {
518                 JRPrintElement element = (JRPrintElement) it.next();
519                 cacheInContext(element);
520             }
521         }
522     }
523
524     
525     protected void cacheInContext(JRPrintElement element)
526     {
527         if (element instanceof JRTemplatePrintElement)
528         {
529             JRTemplatePrintElement templateElement = (JRTemplatePrintElement) element;
530             JRTemplateElement template = templateElement.getTemplate();
531             if (template != null)
532             {
533                 virtualizationContext.cacheTemplate(template);
534             }
535         }
536         
537         if (element instanceof JRPrintFrame)
538         {
539             JRPrintFrame frame = (JRPrintFrame) element;
540             cacheInContext(frame.getElements());
541         }
542     }
543
544     public void afterInternalization()
545     {
546         restoreElementsData();
547     }
548
549
550     protected void restoreElementsData()
551     {
552         traverseDeepElements(new InternalizationElementVisitor());
553     }
554
555
556     public JRVirtualizationContext getContext()
557     {
558         return virtualizationContext;
559     }
560
561
562     public void afterExternalization()
563     {
564         restoreElementsData();
565     }
566     
567     
568     /**
569      * Traverses all the elements on the page, including the ones placed inside
570      * {@link JRPrintFrame frames}.
571      *
572      * @param visitor element visitor
573      */

574     protected void traverseDeepElements(ElementVisitor visitor)
575     {
576         traverseDeepElements(visitor, elements);
577     }
578
579     protected void traverseDeepElements(ElementVisitor visitor, List JavaDoc elementsList)
580     {
581         for (Iterator JavaDoc it = elementsList.iterator(); it.hasNext();)
582         {
583             JRPrintElement element = (JRPrintElement) it.next();
584             visitor.visitElement(element);
585             
586             if (element instanceof JRPrintFrame)
587             {
588                 JRPrintFrame frame = (JRPrintFrame) element;
589                 traverseDeepElements(visitor, frame.getElements());
590             }
591         }
592     }
593     
594     protected static interface ElementVisitor
595     {
596         void visitElement(JRPrintElement element);
597     }
598     
599     
600     protected class ExternalizationElementVisitor implements ElementVisitor
601     {
602         private final Map JavaDoc idTemplates = new HashMap JavaDoc();
603
604         public void visitElement(JRPrintElement element)
605         {
606             // replacing element template with dummy template that only stores the template ID
607
if (element instanceof JRTemplatePrintElement)
608             {
609                 setExternalizationTemplate((JRTemplatePrintElement) element);
610             }
611             
612             // replacing image renderer cached in the virtualization context
613
// with dummy renderer that only stores the renderer ID
614
if (element instanceof JRPrintImage)
615             {
616                 setExternalizationRenderer((JRPrintImage) element);
617             }
618         }
619
620         protected void setExternalizationTemplate(JRTemplatePrintElement templateElement)
621         {
622             JRTemplateElement template = templateElement.getTemplate();
623             if (template != null)
624             {
625                 if (virtualizationContext.hasCachedTemplate(template.getId()))
626                 {
627                     String JavaDoc templateId = template.getId();
628                     JRIdHolderTemplateElement idTemplate = (JRIdHolderTemplateElement) idTemplates.get(templateId);
629                     if (idTemplate == null)
630                     {
631                         idTemplate = new JRIdHolderTemplateElement(templateId);
632                         idTemplates.put(templateId, idTemplate);
633                     }
634                     templateElement.setTemplate(idTemplate);
635                 }
636                 else
637                 {
638                     if (log.isDebugEnabled())
639                     {
640                         log.debug("Template " + template + " having id " + template.getId() + " not found in virtualization context cache");
641                     }
642                 }
643             }
644         }
645     }
646     
647     protected class InternalizationElementVisitor implements ElementVisitor
648     {
649
650         public void visitElement(JRPrintElement element)
651         {
652             if (element instanceof JRTemplatePrintElement)
653             {
654                 // restore the cached element template from the virtualization context
655
restoreTemplate((JRTemplatePrintElement) element);
656             }
657             
658             if (element instanceof JRPrintImage)
659             {
660                 // restore the cached image rendere from the virtualization context
661
restoreRenderer((JRPrintImage) element);
662             }
663         }
664
665         protected void restoreTemplate(JRTemplatePrintElement element)
666         {
667             JRTemplateElement template = element.getTemplate();
668             if (template != null && template instanceof JRIdHolderTemplateElement)
669             {
670                 JRTemplateElement cachedTemplate = virtualizationContext.getCachedTemplate(template.getId());
671                 if (cachedTemplate == null)
672                 {
673                     throw new JRRuntimeException("Template " + template.getId() + " not found in virtualization context.");
674                 }
675
676                 element.setTemplate(cachedTemplate);
677             }
678         }
679
680         protected void restoreRenderer(JRPrintImage image)
681         {
682             JRRenderable renderer = image.getRenderer();
683             if (renderer != null && renderer instanceof JRIdHolderRenderer)
684             {
685                 JRRenderable cachedRenderer = virtualizationContext.getCachedRenderer(renderer.getId());
686                 if (cachedRenderer == null)
687                 {
688                     throw new JRRuntimeException("Renderer " + renderer.getId() + " not found in virtualization context.");
689                 }
690                 image.setRenderer(cachedRenderer);
691             }
692         }
693     }
694 }
695
Popular Tags