IDEMPIERE-146 Performance: Report Engine always read all data into memory

This commit is contained in:
Heng Sin Low 2012-07-01 09:27:13 +08:00
parent e0e7d05167
commit 809f57fe77
13 changed files with 862 additions and 124 deletions

View File

@ -0,0 +1,16 @@
-- Jun 30, 2012 9:04:20 AM MYT
-- IDEMPIERE-146 Performance: Report Engine always read all data into memory
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_SysConfig_UU,ConfigurationLevel,Value,Description,EntityType,AD_Client_ID,Created,Updated,AD_Org_ID,CreatedBy,UpdatedBy,IsActive,Name) VALUES (200010,'794a49c8-c127-4e9c-bb3f-7be83f42aa48','S','2000','Use swap file when report data exceed the number of rows define here. Enter a value of zero or less if you don''t want to use swap file for all reports regarding the number of rows involved','D',0,TO_DATE('2012-06-30 09:04:18','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2012-06-30 09:04:18','YYYY-MM-DD HH24:MI:SS'),0,100,100,'Y','REPORT_SWAP_MAX_ROWS')
;
-- Jun 30, 2012 9:09:35 AM MYT
-- IDEMPIERE-146 Performance: Report Engine always read all data into memory
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_SysConfig_UU,ConfigurationLevel,Value,Description,EntityType,AD_Client_ID,Created,Updated,AD_Org_ID,CreatedBy,UpdatedBy,IsActive,Name) VALUES (200011,'2f885a17-b05f-4744-a617-20e8449c22df','S','100','Max number of pages to keep in memory when rendering a jasper report','D',0,TO_DATE('2012-06-30 09:09:34','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2012-06-30 09:09:34','YYYY-MM-DD HH24:MI:SS'),0,100,100,'Y','JASPER_REPORT_SWAP_MAX_PAGES')
;
UPDATE AD_System
SET LastMigrationScriptApplied='848_IDEMPIERE-146.sql'
WHERE LastMigrationScriptApplied<'848_IDEMPIERE-146.sql'
OR LastMigrationScriptApplied IS NULL
;

View File

@ -0,0 +1,16 @@
-- Jun 30, 2012 9:04:20 AM MYT
-- IDEMPIERE-146 Performance: Report Engine always read all data into memory
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_SysConfig_UU,ConfigurationLevel,Value,Description,EntityType,AD_Client_ID,Created,Updated,AD_Org_ID,CreatedBy,UpdatedBy,IsActive,Name) VALUES (200010,'794a49c8-c127-4e9c-bb3f-7be83f42aa48','S','2000','Use swap file when report data exceed the number of rows define here. Enter a value of zero or less if you don''t want to use swap file for all reports regarding the number of rows involved','D',0,TO_TIMESTAMP('2012-06-30 09:04:18','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2012-06-30 09:04:18','YYYY-MM-DD HH24:MI:SS'),0,100,100,'Y','REPORT_SWAP_MAX_ROWS')
;
-- Jun 30, 2012 9:09:35 AM MYT
-- IDEMPIERE-146 Performance: Report Engine always read all data into memory
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_SysConfig_UU,ConfigurationLevel,Value,Description,EntityType,AD_Client_ID,Created,Updated,AD_Org_ID,CreatedBy,UpdatedBy,IsActive,Name) VALUES (200011,'2f885a17-b05f-4744-a617-20e8449c22df','S','100','Max number of pages to keep in memory when rendering a jasper report','D',0,TO_TIMESTAMP('2012-06-30 09:09:34','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2012-06-30 09:09:34','YYYY-MM-DD HH24:MI:SS'),0,100,100,'Y','JASPER_REPORT_SWAP_MAX_PAGES')
;
UPDATE AD_System
SET LastMigrationScriptApplied='848_IDEMPIERE-146.sql'
WHERE LastMigrationScriptApplied<'848_IDEMPIERE-146.sql'
OR LastMigrationScriptApplied IS NULL
;

View File

@ -19,6 +19,7 @@ package org.compiere.print;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
@ -32,6 +33,8 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.compiere.Adempiere;
import org.compiere.print.util.SerializableMatrix;
import org.compiere.print.util.SerializableMatrixImpl;
import org.compiere.util.CLogger;
import org.compiere.util.DisplayType;
import org.compiere.util.Trace;
@ -67,6 +70,7 @@ public class PrintData implements Serializable
throw new IllegalArgumentException("Name cannot be null");
m_ctx = ctx;
m_name = name;
m_matrix = new SerializableMatrixImpl<Serializable>(name);
} // PrintData
/**
@ -80,21 +84,18 @@ public class PrintData implements Serializable
if (name == null)
throw new IllegalArgumentException("Name cannot be null");
m_ctx = ctx;
m_name = name;
m_name = name;
m_matrix = new SerializableMatrixImpl<Serializable>(name);
if (nodes != null)
m_nodes = nodes;
addRow(false, 0, nodes);
} // PrintData
private SerializableMatrix<Serializable> m_matrix;
/** Context */
private Properties m_ctx;
/** Data Structure Name */
private String m_name;
/** Data Structure rows */
private ArrayList<ArrayList<Serializable>> m_rows = new ArrayList<ArrayList<Serializable>>();
/** Current Row Data Structure elements */
private ArrayList<Serializable> m_nodes = null;
/** Current Row */
private int m_row = -1;
/** List of Function Rows */
private ArrayList<Integer> m_functionRows = new ArrayList<Integer>();
@ -207,7 +208,7 @@ public class PrintData implements Serializable
public String toString()
{
StringBuffer sb = new StringBuffer("PrintData[");
sb.append(m_name).append(",Rows=").append(m_rows.size());
sb.append(m_name).append(",Rows=").append(m_matrix.getRowCount());
if (m_TableName != null)
sb.append(",TableName=").append(m_TableName);
sb.append("]");
@ -222,9 +223,7 @@ public class PrintData implements Serializable
*/
public boolean isEmpty()
{
if (m_nodes == null)
return true;
return m_nodes.size() == 0;
return m_matrix.getRowCount() == 0 || m_matrix.getRowData().isEmpty();
} // isEmpty
/**
@ -233,24 +232,27 @@ public class PrintData implements Serializable
*/
public int getNodeCount()
{
if (m_nodes == null)
if (m_matrix.getRowCount() == 0)
return 0;
return m_nodes.size();
return m_matrix.getRowData().size();
} // getNodeCount
public void addRow (boolean functionRow, int levelNo)
{
addRow(functionRow, levelNo, new ArrayList<Serializable>());
}
/**************************************************************************
* Add Row
* @param functionRow true if function row
* @param levelNo Line detail Level Number 0=Normal
*/
public void addRow (boolean functionRow, int levelNo)
public void addRow (boolean functionRow, int levelNo, List<Serializable> nodes)
{
m_nodes = new ArrayList<Serializable>();
m_row = m_rows.size();
m_rows.add (m_nodes);
m_matrix.addRow(nodes);
if (functionRow)
m_functionRows.add(new Integer(m_row));
m_functionRows.add(new Integer(m_matrix.getRowIndex()));
if (m_hasLevelNo && levelNo != 0)
addNode(new PrintDataElement(LEVEL_NO, new Integer(levelNo), DisplayType.Integer, null));
} // addRow
@ -262,11 +264,7 @@ public class PrintData implements Serializable
*/
public boolean setRowIndex (int row)
{
if (row < 0 || row >= m_rows.size())
return false;
m_row = row;
m_nodes = m_rows.get(m_row);
return true;
return m_matrix.setRowIndex(row);
}
/**
@ -275,7 +273,7 @@ public class PrintData implements Serializable
*/
public boolean setRowNext()
{
return setRowIndex(m_row+1);
return m_matrix.setRowNext();
} // setRowNext
/**
@ -284,7 +282,7 @@ public class PrintData implements Serializable
*/
public int getRowCount()
{
return m_rows.size();
return m_matrix.getRowCount();
} // getRowCount
/**
@ -293,7 +291,7 @@ public class PrintData implements Serializable
*/
public int getRowIndex()
{
return m_row;
return m_matrix.getRowCount();
} // getRowIndex
/**
@ -312,7 +310,7 @@ public class PrintData implements Serializable
*/
public boolean isFunctionRow ()
{
return m_functionRows.contains(new Integer(m_row));
return m_functionRows.contains(new Integer(m_matrix.getRowIndex()));
} // isFunctionRow
/**
@ -322,11 +320,12 @@ public class PrintData implements Serializable
public boolean isPageBreak ()
{
// page break requires function and meta data
if (isFunctionRow() && m_nodes != null)
List<Serializable> nodes = m_matrix.getRowData();
if (isFunctionRow() && nodes != null)
{
for (int i = 0; i < m_nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Object o = m_nodes.get(i);
Object o = nodes.get(i);
if (o instanceof PrintDataElement)
{
PrintDataElement pde = (PrintDataElement)o;
@ -362,12 +361,13 @@ public class PrintData implements Serializable
*/
public int getLineLevelNo ()
{
if (m_nodes == null || !m_hasLevelNo)
List<Serializable> nodes = m_matrix.getRowData();
if (nodes == null || !m_hasLevelNo)
return 0;
for (int i = 0; i < m_nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Object o = m_nodes.get (i);
Object o = nodes.get (i);
if (o instanceof PrintDataElement)
{
PrintDataElement pde = (PrintDataElement)o;
@ -391,9 +391,12 @@ public class PrintData implements Serializable
{
if (parent == null)
throw new IllegalArgumentException("Parent cannot be null");
if (m_nodes == null)
addRow(false, 0);
m_nodes.add (parent);
List<Serializable> nodes = m_matrix.getRowData();
if (nodes == null) {
nodes = new ArrayList<Serializable>();
addRow(false, 0, nodes);
}
nodes.add (parent);
} // addNode
/**
@ -404,9 +407,12 @@ public class PrintData implements Serializable
{
if (node == null)
throw new IllegalArgumentException("Node cannot be null");
if (m_nodes == null)
addRow(false, 0);
m_nodes.add (node);
List<Serializable> nodes = m_matrix.getRowData();
if (nodes == null) {
nodes = new ArrayList<Serializable>();
addRow(false, 0, nodes);
}
nodes.add (node);
} // addNode
/**
@ -416,9 +422,10 @@ public class PrintData implements Serializable
*/
public Object getNode (int index)
{
if (m_nodes == null || index < 0 || index >= m_nodes.size())
List<Serializable> nodes = m_matrix.getRowData();
if (nodes == null || index < 0 || index >= nodes.size())
return null;
return m_nodes.get(index);
return nodes.get(index);
} // getNode
/**
@ -431,7 +438,8 @@ public class PrintData implements Serializable
int index = getIndex (name);
if (index < 0)
return null;
return m_nodes.get(index);
List<Serializable> nodes = m_matrix.getRowData();
return nodes.get(index);
} // getNode
/**
@ -444,7 +452,8 @@ public class PrintData implements Serializable
int index = getIndex (AD_Column_ID.intValue());
if (index < 0)
return null;
return m_nodes.get(index);
List<Serializable> nodes = m_matrix.getRowData();
return nodes.get(index);
} // getNode
/**
@ -453,11 +462,12 @@ public class PrintData implements Serializable
*/
public PrintDataElement getPKey()
{
if (m_nodes == null)
List<Serializable> nodes = m_matrix.getRowData();
if (nodes == null)
return null;
for (int i = 0; i < m_nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Object o = m_nodes.get(i);
Object o = nodes.get(i);
if (o instanceof PrintDataElement)
{
PrintDataElement pde = (PrintDataElement)o;
@ -475,11 +485,12 @@ public class PrintData implements Serializable
*/
public int getIndex (String columnName)
{
if (m_nodes == null)
List<Serializable> nodes = m_matrix.getRowData();
if (nodes == null)
return -1;
for (int i = 0; i < m_nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Object o = m_nodes.get(i);
Object o = nodes.get(i);
if (o instanceof PrintDataElement)
{
if (columnName.equals(((PrintDataElement)o).getColumnName()))
@ -540,7 +551,7 @@ public class PrintData implements Serializable
*/
public void dumpCurrentRow()
{
dumpRow(this, m_row);
dumpRow(this, m_matrix.getRowIndex());
} // dump
/**
@ -769,7 +780,7 @@ public class PrintData implements Serializable
PrintData pdx = new PrintData(new Properties(), "test2");
pdx.addNode(new PrintDataElement("test2element1-1","testvalue11",0,null));
pdx.addNode(new PrintDataElement("test2element1-2","testvalue12",0,null));
pdx.addRow(false, 0);
pdx.addRow(false, 0, new ArrayList<Serializable>());
pdx.addNode(new PrintDataElement("test2element2-1","testvalue21",0,null));
pdx.addNode(new PrintDataElement("test2element2-2","testvalue22",0,null));

View File

@ -18,6 +18,7 @@ package org.compiere.print.layout;
import java.awt.Dimension;
import java.awt.geom.Dimension2D;
import java.io.Serializable;
/**
* 2D Dimesnion Implementation
@ -25,8 +26,13 @@ import java.awt.geom.Dimension2D;
* @author Jorg Janke
* @version $Id: Dimension2DImpl.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $
*/
public class Dimension2DImpl extends Dimension2D
public class Dimension2DImpl extends Dimension2D implements Serializable
{
/**
* generated serial id
*/
private static final long serialVersionUID = -6718670551461826020L;
/**
* Constructor 0/0
*/

View File

@ -19,6 +19,12 @@ package org.compiere.print.layout;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.logging.Level;
@ -41,8 +47,13 @@ import org.compiere.util.CLogger;
* @author Jorg Janke
* @version $Id: HTMLRenderer.java,v 1.3 2006/07/30 00:53:02 jjanke Exp $
*/
public class HTMLRenderer extends View
public class HTMLRenderer extends View implements Externalizable
{
/**
* generated serial id
*/
private static final long serialVersionUID = 7180048200607805705L;
/**
* Get View from HTML String
* @param html html string
@ -74,6 +85,10 @@ public class HTMLRenderer extends View
/** Logger */
private static CLogger log = CLogger.getCLogger(HTMLRenderer.class);
public HTMLRenderer() {
super(null);
}
/**************************************************************************
* Constructor
* @param f factory
@ -85,14 +100,18 @@ public class HTMLRenderer extends View
m_factory = f;
m_view = v;
m_view.setParent(this);
m_element = m_view.getElement();
// initially layout to the preferred size
setSize(m_view.getPreferredSpan(X_AXIS), m_view.getPreferredSpan(Y_AXIS));
} // HTMLRenderer
private int m_width;
private View m_view;
private ViewFactory m_factory;
private View m_view;
private ViewFactory m_factory;
private Element m_element;
private Rectangle m_allocation;
private float m_viewWidth;
private float m_viewHeight;
/**
@ -378,6 +397,8 @@ public class HTMLRenderer extends View
public void setSize(float width, float height)
{
this.m_width = (int) width;
this.m_viewWidth = width;
this.m_viewHeight = height;
m_view.setSize(width, height);
}
@ -396,4 +417,25 @@ public class HTMLRenderer extends View
return m_factory;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(m_element);
out.writeObject(m_allocation);
out.writeFloat(m_viewWidth);
out.writeFloat(m_viewHeight);
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
m_element = (Element) in.readObject();
m_allocation = (Rectangle) in.readObject();
HTMLEditorKit kit = new HTMLEditorKit();
m_factory = kit.getViewFactory();
m_view = m_factory.create(m_element);
m_view.setParent(this);
float width = in.readFloat();
float height = in.readFloat();
setSize(width, height);
}
} // HTMLRenderer

View File

@ -34,6 +34,7 @@ import java.awt.print.PrinterJob;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.net.URL;
import java.sql.Timestamp;
import java.util.ArrayList;
@ -61,6 +62,8 @@ import org.compiere.print.MPrintPaper;
import org.compiere.print.MPrintTableFormat;
import org.compiere.print.PrintData;
import org.compiere.print.PrintDataElement;
import org.compiere.print.util.SerializableMatrix;
import org.compiere.print.util.SerializableMatrixImpl;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
@ -1647,8 +1650,7 @@ public class LayoutEngine implements Pageable, Printable, Doc
// The Data
int rows = printData.getRowCount();
// System.out.println("Rows=" + rows);
Object[][] data = new Object [rows][columnCount];
SerializableMatrix<Serializable> elements = new SerializableMatrixImpl<Serializable>(m_PrintInfo.getName());
KeyNamePair[] pk = new KeyNamePair[rows];
String pkColumnName = null;
ArrayList<Integer> functionRows = new ArrayList<Integer>();
@ -1657,7 +1659,7 @@ public class LayoutEngine implements Pageable, Printable, Doc
// for all rows
for (int row = 0; row < rows; row++)
{
// System.out.println("row=" + row);
ArrayList<Serializable> columns = new ArrayList<Serializable>();
printData.setRowIndex(row);
if (printData.isFunctionRow())
{
@ -1690,33 +1692,33 @@ public class LayoutEngine implements Pageable, Printable, Doc
}
}
// for all columns
col = 0;
for (int c = 0; c < format.getItemCount(); c++)
{
Serializable columnElement = null;
MPrintFormatItem item = format.getItem(c);
Object dataElement = null;
Serializable dataElement = null;
if (item.isPrinted()) // Text Columns
{
if (item.isTypeImage())
{
if (item.isImageField())
data[row][col] = createImageElement (item, printData);
columnElement = createImageElement (item, printData);
else if (item.isImageIsAttached())
data[row][col] = ImageElement.get (item.get_ID());
columnElement = ImageElement.get (item.get_ID());
else
data[row][col] = ImageElement.get (item.getImageURL());
if (data[row][col] != null)
((PrintElement)data[row][col]).layout(item.getMaxWidth(), item.getMaxHeight(), false, item.getFieldAlignmentType());
columnElement = ImageElement.get (item.getImageURL());
if (columnElement != null)
((PrintElement)columnElement).layout(item.getMaxWidth(), item.getMaxHeight(), false, item.getFieldAlignmentType());
}
else if (item.isBarcode())
{
data[row][col] = createBarcodeElement(item, printData);
if (data[row][col] != null)
((PrintElement)data[row][col]).layout(item.getMaxWidth(), item.getMaxHeight(), false, item.getFieldAlignmentType());
columnElement = createBarcodeElement(item, printData);
if (columnElement != null)
((PrintElement)columnElement).layout(item.getMaxWidth(), item.getMaxHeight(), false, item.getFieldAlignmentType());
}
else if (item.isTypeText() )
{
data[row][col] = item.getPrintName(format.getLanguage());
columnElement = item.getPrintName(format.getLanguage());
}
else if (item.isTypeField())
{
@ -1729,22 +1731,22 @@ public class LayoutEngine implements Pageable, Printable, Doc
{
PrintDataElement pde = (PrintDataElement)obj;
if (pde.isID() || pde.isYesNo())
dataElement = pde.getValue();
dataElement = (Serializable) pde.getValue();
else
dataElement = pde.getValueDisplay(format.getLanguage());
}
}
else
log.log(Level.SEVERE, "Element not PrintDataElement " + obj.getClass());
// System.out.println(" row=" + row + ",col=" + col + " - " + item.getAD_Column_ID() + " => " + dataElement);
data[row][col] = dataElement;
columnElement = dataElement;
}
else // item.isTypeBox() or isTypePrintFormat()
{
log.warning("Unsupported: " + (item.isTypeBox() ? "Box" : "PrintFormat") + " in Table: " + item);
}
col++;
columns.add(columnElement);
} // printed
} // for all columns
elements.addRow(columns);
PrintDataElement pde = printData.getPKey();
if (pde != null) // for FunctionRows
@ -1761,7 +1763,7 @@ public class LayoutEngine implements Pageable, Printable, Doc
TableElement table = new TableElement(columnHeader,
columnMaxWidth, columnMaxHeight, columnJustification,
fixedWidth, functionRows, multiLineHeader,
data, pk, pkColumnName,
elements, pk, pkColumnName,
pageNoStart, firstPage, nextPages, repeatedColumns, additionalLines,
rowColFont, rowColColor, rowColBackground,
tf, pageBreak, colSuppressRepeats);

View File

@ -24,6 +24,7 @@ import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.geom.Point2D;
import java.awt.image.ImageObserver;
import java.io.Serializable;
import java.util.Properties;
import java.util.logging.Level;
@ -38,8 +39,14 @@ import org.compiere.util.CLogger;
* @author Jorg Janke
* @version $Id: PrintElement.java,v 1.2 2006/07/30 00:53:02 jjanke Exp $
*/
public abstract class PrintElement implements ImageObserver
public abstract class PrintElement implements ImageObserver, Serializable
{
/**
* generated serial id
*/
private static final long serialVersionUID = 5894090289966933777L;
/**
* Constructor
*/

View File

@ -30,11 +30,13 @@ import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.regex.Pattern;
@ -45,6 +47,8 @@ import net.sourceforge.barbecue.output.OutputException;
import org.compiere.model.MQuery;
import org.compiere.print.MPrintFormatItem;
import org.compiere.print.MPrintTableFormat;
import org.compiere.print.util.SerializableMatrix;
import org.compiere.print.util.SerializableMatrixImpl;
import org.compiere.util.KeyNamePair;
import org.compiere.util.NamePair;
import org.compiere.util.Util;
@ -111,13 +115,16 @@ public class TableElement extends PrintElement
public TableElement (ValueNamePair[] columnHeader,
int[] columnMaxWidth, int[] columnMaxHeight, String[] columnJustification,
boolean[] fixedWidth, ArrayList<Integer> functionRows, boolean multiLineHeader,
Object[][] data, KeyNamePair[] pk, String pkColumnName,
SerializableMatrix<Serializable> data, KeyNamePair[] pk, String pkColumnName,
int pageNoStart, Rectangle firstPage, Rectangle nextPages, int repeatedColumns, HashMap<Integer,Integer> additionalLines,
HashMap<Point,Font> rowColFont, HashMap<Point,Color> rowColColor, HashMap<Point,Color> rowColBackground,
MPrintTableFormat tFormat, ArrayList<Integer> pageBreak, boolean[] colSuppressRepeats)
{
super();
log.fine("Cols=" + columnHeader.length + ", Rows=" + data.length);
if (log.isLoggable(Level.FINE))
{
log.fine("Cols=" + columnHeader.length + ", Rows=" + data.getRowCount());
}
m_colSuppressRepeats = colSuppressRepeats;
m_columnHeader = columnHeader;
m_columnMaxWidth = columnMaxWidth;
@ -191,7 +198,7 @@ public class TableElement extends PrintElement
/** List of Function Rows */
private ArrayList<Integer> m_functionRows;
/** The Data */
private Object[][] m_data;
private SerializableMatrix<Serializable> m_data;
/** Primary Keys */
private KeyNamePair[] m_pk;
/** Primary Key Column Name */
@ -274,16 +281,16 @@ public class TableElement extends PrintElement
return true;
p_width = 0;
m_printRows = new ArrayList<ArrayList<ArrayList<Object>>>(m_data.length); // reset
m_printRows = new SerializableMatrixImpl<ArrayList<Serializable>>("TableElementPrintRows"); // reset
// Max Column Width = 50% of available width (used if maxWidth not set)
float dynMxColumnWidth = m_firstPage.width / 2;
// Width caolculation
int rows = m_data.length;
// Width calculation
int rows = m_data.getRowCount();
int cols = m_columnHeader.length;
// Data Sizes and Header Sizes
Dimension2DImpl[][] dataSizes = new Dimension2DImpl[rows][cols];
SerializableMatrix<Dimension2DImpl> dataSizes = new SerializableMatrixImpl<Dimension2DImpl>("TableElementDimensions");
Dimension2DImpl[] headerSizes = new Dimension2DImpl[cols];
FontRenderContext frc = new FontRenderContext(null, true, true);
@ -300,48 +307,62 @@ public class TableElement extends PrintElement
float colWidth = 0;
for (int row = 0; row < rows; row++)
{
Object dataItem = m_data[row][dataCol];
m_data.setRowIndex(row);
if (dataSizes.getRowCount() <= row)
{
dataSizes.addRow(new ArrayList<Dimension2DImpl>());
}
else
{
dataSizes.setRowIndex(row);
}
List<Dimension2DImpl> dimensions = dataSizes.getRowData();
if (dimensions.size() <= dataCol)
{
dimensions.add(null);
}
Serializable dataItem = m_data.getRowData().get(dataCol);
if (dataItem == null)
{
dataSizes[row][dataCol] = new Dimension2DImpl();
dimensions.set(dataCol, new Dimension2DImpl());
continue;
}
String string = dataItem.toString();
if (string.length() == 0)
{
dataSizes[row][dataCol] = new Dimension2DImpl();
dimensions.set(dataCol, new Dimension2DImpl());
continue;
}
Font font = getFont(row, dataCol);
// Print below existing column = (col != dataCol)
addPrintLines(row, col, dataItem);
dataSizes[row][dataCol] = new Dimension2DImpl(); // don't print
dimensions.set(dataCol, new Dimension2DImpl());
if (dataItem instanceof Boolean)
{
dataSizes[row][col].addBelow(LayoutEngine.IMAGE_SIZE);
dimensions.get(col).addBelow(LayoutEngine.IMAGE_SIZE);
continue;
}
else if (dataItem instanceof ImageElement)
{
dataSizes[row][col].addBelow(
dimensions.get(col).addBelow(
new Dimension((int)((ImageElement)dataItem).getWidth(),
(int)((ImageElement)dataItem).getHeight()));
// Adjust the column width - teo_sarca, [ 1673620 ]
float width = (float)Math.ceil(dataSizes[row][col].getWidth());
float width = (float)Math.ceil(dimensions.get(col).getWidth());
if (colWidth < width)
colWidth = width;
continue;
}
else if (dataItem instanceof BarcodeElement)
{
dataSizes[row][col].addBelow(
dimensions.get(col).addBelow(
new Dimension((int)((BarcodeElement)dataItem).getWidth(),
(int)((BarcodeElement)dataItem).getHeight()));
// Check if the overflow is allowed - teo_sarca, [ 1673590 ]
if (!((BarcodeElement)dataItem).isAllowOverflow()) {
float width = (float)Math.ceil(dataSizes[row][col].getWidth());
float width = (float)Math.ceil(dimensions.get(col).getWidth());
if (colWidth < width)
colWidth = width;
}
@ -362,12 +383,12 @@ public class TableElement extends PrintElement
m_columnMaxWidth[col] = (int)Math.ceil(dynMxColumnWidth);
else if (colWidth < width)
colWidth = width;
if (dataSizes[row][col] == null)
if (dimensions.get(col) == null)
{
dataSizes[row][col] = new Dimension2DImpl();
dimensions.set(col, new Dimension2DImpl());
log.log(Level.WARNING, "No Size for r=" + row + ",c=" + col);
}
dataSizes[row][col].addBelow(width, height);
dimensions.get(col).addBelow(width, height);
}
// Width limitations
if (m_columnMaxWidth[col] != 0 && m_columnMaxWidth[col] != -1)
@ -385,7 +406,7 @@ public class TableElement extends PrintElement
height = renderer.getHeight();
renderer.setAllocation((int)colWidth, (int)height);
// log.finest( "calculateSize HTML - " + renderer.getAllocation());
m_data[row][dataCol] = renderer; // replace for printing
m_data.getRowData().set(dataCol, renderer);
}
else
{
@ -415,14 +436,17 @@ public class TableElement extends PrintElement
}
if (m_fixedWidth[col])
colWidth = Math.abs(m_columnMaxWidth[col]);
dataSizes[row][col].addBelow(colWidth, height);
dimensions.get(col).addBelow(colWidth, height);
}
dataSizes[row][col].roundUp();
dimensions.get(col).roundUp();
if (dataItem instanceof NamePair)
m_rowColDrillDown.put(new Point(row, col), (NamePair)dataItem);
//
log.finest("Col=" + col + ", row=" + row
+ " => " + dataSizes[row][col] + " - ColWidth=" + colWidth);
if (log.isLoggable(Level.FINEST))
{
log.finest("Col=" + col + ", row=" + row
+ " => " + dimensions.get(col) + " - ColWidth=" + colWidth);
}
} // for all data rows
// Column Width for Header
@ -532,10 +556,12 @@ public class TableElement extends PrintElement
for (int row = 0; row < rows; row++)
{
float rowHeight = 0f;
dataSizes.setRowIndex(row);
List<Dimension2DImpl> dimensions = dataSizes.getRowData();
for (int col = 0; col < cols; col++)
{
if (dataSizes[row][col].height > rowHeight) // max
rowHeight = (float)dataSizes[row][col].height;
if (dimensions.get(col).height > rowHeight) // max
rowHeight = (float)dimensions.get(col).height;
} // for all columns
rowHeight += m_tFormat.getLineStroke().floatValue() + (2*V_GAP);
m_rowHeights.add(new Float(rowHeight));
@ -1080,7 +1106,7 @@ public class TableElement extends PrintElement
return -1; // above
//
int firstRow = ((Integer)m_firstRowOnPage.get(pageYindex)).intValue();
int nextPageRow = m_data.length; // no of rows
int nextPageRow = m_data.getRowCount(); // no of rows
if (pageYindex+1 < m_firstRowOnPage.size())
nextPageRow = ((Integer)m_firstRowOnPage.get(pageYindex+1)).intValue();
//
@ -1162,7 +1188,7 @@ public class TableElement extends PrintElement
nextPageColumn = ((Integer)m_firstColumnOnPage.get(pageXindex+1)).intValue();
//
int firstRow = ((Integer)m_firstRowOnPage.get(pageYindex)).intValue();
int nextPageRow = m_data.length; // no of rows
int nextPageRow = m_data.getRowCount(); // no of rows
if (pageYindex+1 < m_firstRowOnPage.size())
nextPageRow = ((Integer)m_firstRowOnPage.get(pageYindex+1)).intValue();
if (DEBUG_PRINT)
@ -1557,7 +1583,7 @@ public class TableElement extends PrintElement
curX += m_tFormat.getVLineStroke().floatValue();
// X end line
if (row == m_data.length-1) // last Line
if (row == m_data.getRowCount()-1) // last Line
{
/**
* Bug fix - Bottom line was always displayed whether or not header lines was set to be visible
@ -1608,30 +1634,34 @@ public class TableElement extends PrintElement
* @param col col
* @param data data
*/
private void addPrintLines (int row, int col, Object data)
private void addPrintLines (int row, int col, Serializable data)
{
while (m_printRows.size() <= row)
m_printRows.add(null);
ArrayList<ArrayList<Object>> columns = m_printRows.get(row);
while (m_printRows.getRowCount() <= row)
m_printRows.addRow(null);
m_printRows.setRowIndex(row);
List<ArrayList<Serializable>> columns = m_printRows.getRowData();
if (columns == null)
columns = new ArrayList<ArrayList<Object>>(m_columnHeader.length);
columns = new ArrayList<ArrayList<Serializable>>(m_columnHeader.length);
while (columns.size() <= col)
columns.add(null);
//
ArrayList<Object> coordinate = columns.get(col);
ArrayList<Serializable> coordinate = columns.get(col);
if (coordinate == null)
coordinate = new ArrayList<Object>();
coordinate = new ArrayList<Serializable>();
coordinate.add(data);
//
columns.set(col, coordinate);
m_printRows.set(row, columns);
log.finest("row=" + row + ", col=" + col
+ " - Rows=" + m_printRows.size() + ", Cols=" + columns.size()
+ " - " + data);
m_printRows.setRowData(columns);
if (log.isLoggable(Level.FINEST))
{
log.finest("row=" + row + ", col=" + col
+ " - Rows=" + m_printRows.getRowCount() + ", Cols=" + columns.size()
+ " - " + data);
}
} // addAdditionalLines
/** Print Data */
private ArrayList<ArrayList<ArrayList<Object>>> m_printRows = new ArrayList<ArrayList<ArrayList<Object>>>();
private SerializableMatrix<ArrayList<Serializable>> m_printRows = new SerializableMatrixImpl<ArrayList<Serializable>>("PrintRows");
/**
* Insert empty Row after current Row
@ -1651,12 +1681,15 @@ public class TableElement extends PrintElement
*/
private Object[] getPrintItems (int row, int col)
{
ArrayList<ArrayList<Object>> columns = null;
if (m_printRows.size() > row)
columns = m_printRows.get(row);
List<ArrayList<Serializable>> columns = null;
if (m_printRows.getRowCount() > row)
{
m_printRows.setRowIndex(row);
columns = m_printRows.getRowData();
}
if (columns == null)
return new Object[]{};
ArrayList<Object> coordinate = null;
ArrayList<Serializable> coordinate = null;
if (columns.size() > col)
coordinate = columns.get(col);
if (coordinate == null)

View File

@ -0,0 +1,46 @@
/******************************************************************************
* Copyright (C) 2012 Heng Sin Low *
* Copyright (C) 2012 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program 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 General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.compiere.print.util;
import java.io.Serializable;
import java.util.List;
public interface SerializableMatrix<T extends Serializable> {
public void addRow(List<T> data);
public boolean setRowIndex(int row);
/**
* Set Row Index to next
* @return true if success
*/
public boolean setRowNext(); // setRowNext
/**
* Get Row Count
* @return row count
*/
public int getRowCount(); // getRowCount
/**
* Get Current Row Index
* @return row index
*/
public int getRowIndex(); // getRowIndex
public List<T> getRowData();
public void setRowData(List<T> data);
}

View File

@ -0,0 +1,250 @@
/******************************************************************************
* Copyright (C) 2012 Heng Sin Low *
* Copyright (C) 2012 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program 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 General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.compiere.print.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.compiere.model.MSysConfig;
import org.compiere.util.CLogger;
/**
*
* @author hengsin
*
*/
public class SerializableMatrixImpl<T extends Serializable> implements SerializableMatrix<T> {
/** default 4k block size **/
private static final int DEFAULT_BLOCK_SIZE = 4*1024;
/** Default to start swapping after 2k row **/
private static final int DEFAULT_SWAP_MAX_ROWS = 2000;
/** set to 0 or smaller to disable swap file usage **/
private static final String REPORT_SWAP_MAX_ROWS = "REPORT_SWAP_MAX_ROWS";
private static final CLogger log = CLogger.getCLogger(SerializableMatrixImpl.class);
/** Data Structure rows */
private ArrayList<List<T>> m_rows = new ArrayList<List<T>>();
/** Current Row */
private int m_currentRow = -1;
private int m_pageSize = 0;
private int m_size = 0;
private Page currentPage = null;
private List<SwapFileSegment> segments = new ArrayList<SwapFileSegment>();
private List<Page> pages = new ArrayList<Page>();
private SwapFile swapFile;
private String prefix;
public SerializableMatrixImpl(String name) {
this.prefix = name;
int pageSize = MSysConfig.getIntValue(REPORT_SWAP_MAX_ROWS, DEFAULT_SWAP_MAX_ROWS);
if (pageSize <= 0) {
m_pageSize = Integer.MAX_VALUE;
} else {
m_pageSize = pageSize;
}
}
/* (non-Javadoc)
* @see org.compiere.print.util.SerializableDataTable#addRow(java.util.ArrayList)
*/
@Override
public void addRow(List<T> data) {
m_size++;
if (currentPage == null) {
currentPage = new Page();
pages.add(currentPage);
currentPage.first = 0;
currentPage.last = 0;
currentPage.size = 1;
currentPage.pageNo = pages.size() - 1;
m_rows.add(data);
m_currentRow = 0;
} else {
Page lastPage = pages.get(pages.size() - 1);
if (lastPage.size == m_pageSize) {
pageout(currentPage);
currentPage = new Page();
pages.add(currentPage);
currentPage.pageNo = pages.size() - 1;
currentPage.first = lastPage.last + 1;
currentPage.last = currentPage.first;
currentPage.size = 1;
m_rows = new ArrayList<List<T>>();
m_rows.add(data);
m_currentRow = currentPage.first;
} else {
if (currentPage.pageNo != lastPage.pageNo) {
pageout(currentPage);
pagein(lastPage.pageNo);
}
m_rows.add(data);
currentPage.last++;
currentPage.size++;
m_currentRow = currentPage.last;
}
}
}
/* (non-Javadoc)
* @see org.compiere.print.util.SerializableDataTable#setRowIndex(int)
*/
@Override
public boolean setRowIndex (int row) {
if (row < 0 || row >= m_size)
return false;
if (row >= currentPage.first && row <= currentPage.last) {
m_currentRow = row;
return true;
} else {
Page tmp = currentPage;
for(Page page : pages) {
if (row >= page.first && row <= page.last) {
currentPage = page;
pageout(tmp);
pagein(currentPage.pageNo);
m_currentRow = row;
return true;
}
}
return false;
}
}
/* (non-Javadoc)
* @see org.compiere.print.util.SerializableDataTable#setRowNext()
*/
@Override
public boolean setRowNext()
{
return setRowIndex(m_currentRow+1);
} // setRowNext
/* (non-Javadoc)
* @see org.compiere.print.util.SerializableDataTable#getRowCount()
*/
@Override
public int getRowCount()
{
return m_size;
} // getRowCount
/* (non-Javadoc)
* @see org.compiere.print.util.SerializableDataTable#getRowIndex()
*/
@Override
public int getRowIndex()
{
return m_currentRow;
} // getRowIndex
/* (non-Javadoc)
* @see org.compiere.print.util.SerializableDataTable#getRowData()
*/
@Override
public List<T> getRowData()
{
return m_rows.isEmpty() ? null : m_rows.get(m_currentRow - currentPage.first);
}
@Override
public void setRowData(List<T> data) {
if (currentPage != null) {
int index = m_currentRow - currentPage.first;
if (index < m_rows.size()) {
m_rows.set(index, data);
}
}
}
private void pageout(Page currentPage) {
ByteArrayOutputStream bas = new ByteArrayOutputStream();
try {
ObjectOutputStream ous = new ObjectOutputStream(bas);
ous.writeObject(m_rows);
if (swapFile == null) {
swapFile = new SwapFile(makePrefix(prefix), DEFAULT_BLOCK_SIZE, 2);
}
swapFile.open();
SwapFileSegment segment = swapFile.write(bas.toByteArray());
if (currentPage.pageNo < segments.size())
segments.set(currentPage.pageNo, segment);
else
segments.add(segment);
} catch (IOException e) {
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
} finally {
if (swapFile != null)
swapFile.close();
}
}
private void pagein(int index) {
SwapFileSegment segment = segments.get(index);
try {
swapFile.open();
byte[] data = swapFile.read(segment);
swapFile.free(segment);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
ArrayList<List<T>> rows = (ArrayList<List<T>>) ois.readObject();
this.m_rows = rows;
currentPage = pages.get(index);
m_currentRow = currentPage.first;
} catch (IOException e) {
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
} catch (ClassNotFoundException e) {
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
} finally {
swapFile.close();
}
}
private String makePrefix(String name) {
StringBuffer prefix = new StringBuffer();
char[] nameArray = name.toCharArray();
for (char ch : nameArray) {
if (Character.isLetterOrDigit(ch)) {
prefix.append(ch);
} else {
prefix.append("_");
}
}
return prefix.toString();
}
class Page {
protected int pageNo;
protected int first;
protected int last;
protected int size;
}
}

View File

@ -0,0 +1,260 @@
/******************************************************************************
* Copyright (C) 2012 Heng Sin Low *
* Copyright (C) 2012 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program 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 General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.compiere.print.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.LinkedList;
import java.util.logging.Level;
import org.compiere.util.CLogger;
/**
*
* @author hengsin
*
*/
public class SwapFile
{
private static final CLogger log = CLogger.getCLogger(SwapFile.class);
private final File swapFile;
private RandomAccessFile randomAccessFile;
private final int blockSize;
private final int minBlockToGrow;
private final LinkedList<Long> freeBlocks;
/**
* Creates a swap file.
*
* The file name is generated automatically.
*
* @param prefix the swap file prefix
* @param blockSize the size of the blocks allocated by the swap file
* @param minBlockToGrow the minimum number of blocks by which the swap file grows when full
*/
public SwapFile(String prefix, int blockSize, int minBlockToGrow)
{
try
{
swapFile = File.createTempFile(prefix, ".swap");
if (log.isLoggable(Level.INFO))
{
log.info("Creating swap file " + swapFile.getPath());
}
swapFile.deleteOnExit();
this.blockSize = blockSize;
this.minBlockToGrow = minBlockToGrow;
freeBlocks = new LinkedList<Long>();
}
catch (FileNotFoundException e)
{
throw new RuntimeException(e);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
/**
* open for read write
*/
public synchronized void open() {
try {
randomAccessFile = new RandomAccessFile(swapFile, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* close and release file handle
*/
public synchronized void close() {
if (randomAccessFile != null) {
try {
randomAccessFile.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* Allocates an area in the swap file and writes data in it.
*
* @param data the data for which to allocate an area in the file
* @return a handle to the allocated area
* @throws IOException
*/
public SwapFileSegment write(byte[] data) throws IOException
{
verifyOpen();
int blockCount = (data.length - 1) / blockSize + 1;
long[] offsets = allocateFreeBlocks(blockCount);
int lastBlockSize = (data.length - 1) % blockSize + 1;
SwapFileSegment segment = new SwapFileSegment(offsets, lastBlockSize);
for (int i = 0; i < blockCount; ++i)
{
int dataSize = i < blockCount - 1 ? blockSize : lastBlockSize;
int dataOffset = i * blockSize;
write(data, dataSize, dataOffset, offsets[i]);
}
return segment;
}
private synchronized void write(byte[] data, int dataSize, int dataOffset, long fileOffset) throws IOException
{
randomAccessFile.seek(fileOffset);
randomAccessFile.write(data, dataOffset, dataSize);
}
/**
* Reads all the data from an allocated area.
*
* @param segment the allocated segment
* @return the whole data saved in an allocated area
* @throws IOException
*/
public byte[] read(SwapFileSegment segment) throws IOException
{
verifyOpen();
long[] offsets = segment.getOffsets();
int totalLength = (offsets.length - 1) * blockSize + segment.getLastBlockSize();
byte[] data = new byte[totalLength];
for (int i = 0; i < offsets.length; ++i)
{
int dataOffset = i * blockSize;
int dataLength = i < offsets.length - 1 ? blockSize : segment.getLastBlockSize();
read(data, dataOffset, dataLength, offsets[i]);
}
return data;
}
private synchronized void read(byte[] data, int dataOffset, int dataLength, long fileOffset) throws IOException
{
randomAccessFile.seek(fileOffset);
randomAccessFile.readFully(data, dataOffset, dataLength);
}
/**
* Frees an allocated area.
*
* @param segment the allocated segment
*/
public void free(SwapFileSegment segment)
{
verifyOpen();
freeBlocks(segment.getOffsets());
}
private void verifyOpen() {
if (randomAccessFile == null) {
throw new RuntimeException("Swap file not open for read write access");
}
}
/**
* Closes and deletes the swap file.
*/
public void dispose()
{
synchronized (this)
{
if (swapFile.exists())
{
if (log.isLoggable(Level.INFO))
{
log.info("Disposing swap file " + swapFile.getPath());
}
try
{
close();
}
catch (Exception e)
{
log.warning("Not able to close swap file " + swapFile.getPath());
}
if (!swapFile.delete())
{
log.warning("Not able to delete swap file " + swapFile.getPath());
}
}
}
}
protected void finalize() throws Throwable //NOSONAR
{
dispose();
super.finalize();
}
private synchronized long[] allocateFreeBlocks(int blockCount) throws IOException
{
int growCount = blockCount - freeBlocks.size();
if (growCount > 0)
{
if (growCount < minBlockToGrow)
{
growCount = minBlockToGrow;
}
long length = randomAccessFile.length();
long newLength = length + growCount * blockSize;
if (log.isLoggable(Level.INFO))
{
log.info("Growing swap file " + swapFile.getPath() + " with " + growCount + " blocks x " + blockSize + " bytes to size " + newLength);
}
randomAccessFile.setLength(newLength);
for (int i = 0; i < growCount; ++i)
{
freeBlocks.addLast(length + i * blockSize);
}
}
long[] offsets = new long[blockCount];
for (int i = 0; i < blockCount; i++)
{
offsets[i] = freeBlocks.pollFirst();
}
return offsets;
}
private synchronized void freeBlocks(long []offsets)
{
for (int i = offsets.length - 1; i >= 0; --i)
{
freeBlocks.addFirst(offsets[i]);
}
}
}

View File

@ -0,0 +1,40 @@
/******************************************************************************
* Copyright (C) 2012 Heng Sin Low *
* Copyright (C) 2012 Trek Global *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program 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 General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.compiere.print.util;
/**
*
* @author hengsin
*
*/
public class SwapFileSegment {
private final long[] offsets;
private final int lastBlockSize;
public SwapFileSegment(long[] offsets, int lastSize)
{
this.offsets = offsets;
this.lastBlockSize = lastSize;
}
public long[] getOffsets()
{
return offsets;
}
public int getLastBlockSize()
{
return lastBlockSize;
}
}

View File

@ -69,6 +69,7 @@ import org.adempiere.util.IProcessUI;
import org.compiere.model.MAttachment;
import org.compiere.model.MAttachmentEntry;
import org.compiere.model.MProcess;
import org.compiere.model.MSysConfig;
import org.compiere.model.PrintInfo;
import org.compiere.model.X_AD_PInstance_Para;
import org.compiere.print.MPrintFormat;
@ -103,6 +104,8 @@ import org.compiere.utils.DigestOfFile;
*/
public class ReportStarter implements ProcessCall, ClientProcess
{
private static final int DEFAULT_SWAP_MAX_PAGES = 100;
private static final String JASPER_SWAP_MAX_PAGES = "JASPER_REPORT_SWAP_MAX_PAGES";
/** Logger */
private static CLogger log = CLogger.getCLogger(ReportStarter.class);
private static File REPORT_HOME = null;
@ -515,12 +518,14 @@ public class ReportStarter implements ProcessCall, ClientProcess
}
Connection conn = null;
JRSwapFileVirtualizer virtualizer = null;
int maxPages = MSysConfig.getIntValue(JASPER_SWAP_MAX_PAGES, DEFAULT_SWAP_MAX_PAGES);
try {
conn = getConnection();
String swapPath = System.getProperty("java.io.tmpdir");
JRSwapFile swapFile = new JRSwapFile(swapPath, 1024, 1024);
JRSwapFileVirtualizer virtualizer = new JRSwapFileVirtualizer(2, swapFile, true);
virtualizer = new JRSwapFileVirtualizer(maxPages, swapFile, true);
params.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
JRProperties.setProperty("net.sf.jasperreports.awt.ignore.missing.font", true);
@ -593,11 +598,15 @@ public class ReportStarter implements ProcessCall, ClientProcess
} catch (JRException e) {
log.severe("ReportStarter.startProcess: Can not run report - "+ e.getMessage());
} finally {
if (conn != null)
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
if (virtualizer != null) {
virtualizer.cleanup();
}
}
}