From d0d882e11e52b894469ec164003c8a0aa6366d5f Mon Sep 17 00:00:00 2001 From: Lucian Chirita Date: Mon, 10 May 2021 15:33:47 +0300 Subject: [PATCH] fix serialization of virtualized frames fixes gh-156 --- .../engine/base/ElementsBlock.java | 2 +- .../engine/fill/JRTemplatePrintFrame.java | 12 + .../engine/fill/JRVirtualizationContext.java | 67 +- .../fill/VirtualizationContextIdHolder.java | 56 + .../VirtualizedFrames.reference.jrpxml | 1756 +++++++++ .../VirtualizedFramesParent.reference.jrpxml | 3511 +++++++++++++++++ .../VirtualizedFramesParentTest.java | 69 + .../virtualization/VirtualizedFramesTest.java | 67 + .../repo/VirtualizedFrames.jrxml | 53 + .../repo/VirtualizedFramesParent.jrxml | 19 + .../virtualization/repo/empty2.xml | 2 + .../virtualization/repo/empty40.xml | 2 + 12 files changed, 5606 insertions(+), 10 deletions(-) create mode 100644 jasperreports/src/net/sf/jasperreports/engine/fill/VirtualizationContextIdHolder.java create mode 100644 jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFrames.reference.jrpxml create mode 100644 jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFramesParent.reference.jrpxml create mode 100644 jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFramesParentTest.java create mode 100644 jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFramesTest.java create mode 100755 jasperreports/tests/net/sf/jasperreports/virtualization/repo/VirtualizedFrames.jrxml create mode 100755 jasperreports/tests/net/sf/jasperreports/virtualization/repo/VirtualizedFramesParent.jrxml create mode 100644 jasperreports/tests/net/sf/jasperreports/virtualization/repo/empty2.xml create mode 100644 jasperreports/tests/net/sf/jasperreports/virtualization/repo/empty40.xml diff --git a/jasperreports/src/net/sf/jasperreports/engine/base/ElementsBlock.java b/jasperreports/src/net/sf/jasperreports/engine/base/ElementsBlock.java index c5035b8622..ecf5544239 100644 --- a/jasperreports/src/net/sf/jasperreports/engine/base/ElementsBlock.java +++ b/jasperreports/src/net/sf/jasperreports/engine/base/ElementsBlock.java @@ -103,7 +103,7 @@ public void updatePage(JRVirtualPrintPage page) this.page = page; JRVirtualizationContext newContext = page.getVirtualizationContext(); - context.inheritListeners(newContext); + context.updateParent(newContext); } private void lockContext() diff --git a/jasperreports/src/net/sf/jasperreports/engine/fill/JRTemplatePrintFrame.java b/jasperreports/src/net/sf/jasperreports/engine/fill/JRTemplatePrintFrame.java index 2d50b58e10..b4d9178605 100644 --- a/jasperreports/src/net/sf/jasperreports/engine/fill/JRTemplatePrintFrame.java +++ b/jasperreports/src/net/sf/jasperreports/engine/fill/JRTemplatePrintFrame.java @@ -25,6 +25,7 @@ import java.awt.Color; import java.io.IOException; +import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -155,4 +156,15 @@ public void readVirtualized(VirtualizationInput in) throws IOException } } } + + private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException + { + in.defaultReadObject(); + if (elements instanceof VirtualizableElementList) + { + VirtualizableElementList virtualizableList = ((VirtualizableElementList) elements); + JRVirtualizationContext virtualizationContext = virtualizableList.getVirtualizationContext(); + virtualizationContext.cacheVirtualizableList(PrintElementId.forElement(this), virtualizableList); + } + } } diff --git a/jasperreports/src/net/sf/jasperreports/engine/fill/JRVirtualizationContext.java b/jasperreports/src/net/sf/jasperreports/engine/fill/JRVirtualizationContext.java index 60ac690065..8e79f6507a 100644 --- a/jasperreports/src/net/sf/jasperreports/engine/fill/JRVirtualizationContext.java +++ b/jasperreports/src/net/sf/jasperreports/engine/fill/JRVirtualizationContext.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.ReentrantLock; @@ -79,6 +80,8 @@ public class JRVirtualizationContext implements Serializable, VirtualizationList ReferenceMap.ReferenceStrength.WEAK, ReferenceMap.ReferenceStrength.WEAK ); + private UUID id; + private boolean root; private transient JRVirtualizationContext parentContext; private transient JRVirtualizer virtualizer; private transient JasperReportsContext jasperReportsContext; @@ -86,8 +89,10 @@ public class JRVirtualizationContext implements Serializable, VirtualizationList private Map cachedRenderers; private Map cachedTemplates; - private Set frameContexts; - private Map virtualizableLists; + private Map subContexts; + + private transient Set frameContexts; + private transient Map virtualizableLists; private volatile boolean readOnly; private volatile boolean disposed; @@ -105,24 +110,31 @@ public class JRVirtualizationContext implements Serializable, VirtualizationList */ public JRVirtualizationContext(JasperReportsContext jasperReportsContext) { + this.id = UUID.randomUUID(); + this.root = true; this.jasperReportsContext = jasperReportsContext; cachedRenderers = new ConcurrentHashMap(16, 0.75f, 1); cachedTemplates = new ConcurrentHashMap(16, 0.75f, 1); virtualizableLists = new ConcurrentHashMap<>(16, 0.75f, 1); + subContexts = new ConcurrentHashMap<>(16, 0.75f, 1); + subContexts.put(this.id, this); + pageElementSize = JRPropertiesUtil.getInstance(jasperReportsContext).getIntegerProperty(JRVirtualPrintPage.PROPERTY_VIRTUAL_PAGE_ELEMENT_SIZE, 0); initLock(); if (log.isDebugEnabled()) { - log.debug("created " + this); + log.debug("created " + id); } } protected JRVirtualizationContext(JRVirtualizationContext parentContext) { + this.id = UUID.randomUUID(); + this.root = false; this.parentContext = parentContext; this.virtualizer = parentContext.virtualizer; this.jasperReportsContext = parentContext.jasperReportsContext; @@ -131,6 +143,9 @@ protected JRVirtualizationContext(JRVirtualizationContext parentContext) this.cachedRenderers = parentContext.cachedRenderers; this.cachedTemplates = parentContext.cachedTemplates; this.virtualizableLists = parentContext.virtualizableLists; + + this.subContexts = new ConcurrentHashMap<>(16, 0.75f, 1); + this.subContexts.put(this.id, this); this.pageElementSize = parentContext.pageElementSize; @@ -139,7 +154,7 @@ protected JRVirtualizationContext(JRVirtualizationContext parentContext) if (log.isDebugEnabled()) { - log.debug("created sub context " + this + ", parent " + parentContext); + log.debug("created sub context " + id + ", parent " + parentContext.id); } } @@ -413,9 +428,10 @@ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassN setThreadJasperReportsContext(); GetField fields = in.readFields(); + root = fields.get("root", false); cachedRenderers = (Map) fields.get("cachedRenderers", null); cachedTemplates = (Map) fields.get("cachedTemplates", null); - virtualizableLists = (Map) fields.get("virtualizableLists", null); + subContexts = (Map) fields.get("subContexts", null); readOnly = fields.get("readOnly", false); // use configured default if serialized by old version pageElementSize = fields.get("pageElementSize", JRPropertiesUtil.getInstance(jasperReportsContext).getIntegerProperty( @@ -424,6 +440,12 @@ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassN setThreadVirtualizer(); initLock(); + + if (root) + { + virtualizableLists = new ConcurrentHashMap<>(16, 0.75f, 1); + subContexts.values().stream().forEach(context -> {context.virtualizableLists = virtualizableLists;}); + } } private void setThreadVirtualizer() @@ -523,6 +545,18 @@ else if (obj instanceof Renderable) replace = new JRVirtualPrintPage.JRIdHolderRenderer(renderer); } } + else if (obj instanceof JRVirtualizationContext) + { + JRVirtualizationContext context = (JRVirtualizationContext) obj; + if (subContexts.containsKey(context.id)) + { + replace = new VirtualizationContextIdHolder(context.id); + } + else if (log.isDebugEnabled()) + { + log.debug("Context " + context.id + " not found under " + id); + } + } return replace; } @@ -555,6 +589,16 @@ else if (obj instanceof JRVirtualPrintPage.JRIdHolderRenderer) } resolve = cachedRenderer; } + else if (obj instanceof VirtualizationContextIdHolder) + { + UUID id = ((VirtualizationContextIdHolder) obj).getId(); + JRVirtualizationContext context = subContexts.get(id); + if (context == null) + { + throw new JRRuntimeException("Context with ID " + id + " not found"); + } + resolve = context; + } return resolve; } @@ -645,6 +689,9 @@ public JRVirtualizationContext getFramesContext() if (frameContexts.isEmpty()) { frameContext = new JRVirtualizationContext(this); + frameContext.subContexts = subContexts; + subContexts.put(frameContext.id, frameContext); + if (listeners != null) { for (VirtualizationListener listener : listeners) @@ -655,7 +702,7 @@ public JRVirtualizationContext getFramesContext() if (log.isDebugEnabled()) { - log.debug(this + " created frames context " + frameContext); + log.debug(id + " created frames context " + frameContext.id); } frameContexts.add(frameContext); @@ -682,11 +729,13 @@ public VirtualizableElementList getVirtualizableList(PrintElementId id) return virtualizableLists.get(id); } - public void inheritListeners(JRVirtualizationContext sourceContext) + public void updateParent(JRVirtualizationContext destinationContext) { - if (sourceContext.listeners != null) + destinationContext.subContexts.put(id, this); + + if (destinationContext.listeners != null) { - for (VirtualizationListener listener : sourceContext.listeners) + for (VirtualizationListener listener : destinationContext.listeners) { if (listeners == null || !listeners.contains(listener))//TODO keep a set? { diff --git a/jasperreports/src/net/sf/jasperreports/engine/fill/VirtualizationContextIdHolder.java b/jasperreports/src/net/sf/jasperreports/engine/fill/VirtualizationContextIdHolder.java new file mode 100644 index 0000000000..721107e83b --- /dev/null +++ b/jasperreports/src/net/sf/jasperreports/engine/fill/VirtualizationContextIdHolder.java @@ -0,0 +1,56 @@ +/* + * JasperReports - Free Java Reporting Library. + * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved. + * http://www.jaspersoft.com + * + * Unless you have purchased a commercial license agreement from Jaspersoft, + * the following license terms apply: + * + * This program is part of JasperReports. + * + * JasperReports is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * JasperReports is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with JasperReports. If not, see . + */ +package net.sf.jasperreports.engine.fill; + +import java.io.Serializable; +import java.util.UUID; + +import net.sf.jasperreports.engine.JRConstants; + +/** + * + * @author Lucian Chirita (lucianc@users.sourceforge.net) + */ +public class VirtualizationContextIdHolder implements Serializable { + + private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID; + + private UUID id; + + public VirtualizationContextIdHolder() { + } + + public VirtualizationContextIdHolder(UUID id) { + this.id = id; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + +} diff --git a/jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFrames.reference.jrpxml b/jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFrames.reference.jrpxml new file mode 100644 index 0000000000..3b244e37bc --- /dev/null +++ b/jasperreports/tests/net/sf/jasperreports/virtualization/VirtualizedFrames.reference.jrpxml @@ -0,0 +1,1756 @@ + + + + + + +