Jump to content
We've recently updated our Privacy Statement, available here ×

Crosstab misuse or memory leak?


marciopd

Recommended Posts

I'm using crosstabs in a possibly pretty large report.

I designed the report so that the data didn't get all loaded together into memory. Well,  tried :D
The thing is that it seems that there's a problem with jasperreports' crosstab report filling engine (JRFillCrosstab).

Using  a eclipse plugin (http://www.eclipse.org/mat/) to analyse the heap dump on out of memory error, i get that

JRFillCrossTab stores the data in a arraylist that keeps growing and growing...

Code to reproduce the issue is attached.
Class ReportServiceImpl has the main method to be executed.
You should modify the constant ReportServiceImpl.TMP_DIR_PATH to a temporary path in your file system.


Any help please?



Post Edited by marciopd at 07/17/2010 05:04
Link to comment
Share on other sites

  • Replies 9
  • Created
  • Last Reply

Top Posters In This Topic

class that generates the report: ReportServiceImpl.java

Code:
package report;import java.util.HashMap;import java.util.Map;import model.QueryLazyList;import net.sf.jasperreports.engine.JREmptyDataSource;import net.sf.jasperreports.engine.JRException;import net.sf.jasperreports.engine.JRParameter;import net.sf.jasperreports.engine.JRVirtualizer;import net.sf.jasperreports.engine.JasperExportManager;import net.sf.jasperreports.engine.JasperFillManager;import net.sf.jasperreports.engine.JasperPrint;import net.sf.jasperreports.engine.JasperReport;import net.sf.jasperreports.engine.fill.JRSwapFileVirtualizer;import net.sf.jasperreports.engine.util.JRSwapFile;import ar.com.fdvs.dj.core.DJConstants;import ar.com.fdvs.dj.core.DynamicJasperHelper;import ar.com.fdvs.dj.core.layout.ClassicLayoutManager;import ar.com.fdvs.dj.domain.DJCalculation;import ar.com.fdvs.dj.domain.DJCrosstab;import ar.com.fdvs.dj.domain.DynamicReport;import ar.com.fdvs.dj.domain.Style;import ar.com.fdvs.dj.domain.builders.CrosstabBuilder;import ar.com.fdvs.dj.domain.builders.DynamicReportBuilder;import ar.com.fdvs.dj.domain.constants.Border;public class ReportServiceImpl {	/**	 * Tmp dir path.	 */	private static final String TMP_DIR_PATH = "/tmp";	/**	 * Generates test report.	 * @return	 * @throws JRException erro	 */	public byte[] generateCrossTabReport() throws JRException {		DynamicReportBuilder drb = new DynamicReportBuilder();;		DJCrosstab djcross = new CrosstabBuilder().setHeight(200).setWidth(500)				.setDatasource("sr",						DJConstants.DATA_SOURCE_ORIGIN_PARAMETER,						DJConstants.DATA_SOURCE_TYPE_COLLECTION,						true)				.setUseFullWidth(true)				.setAutomaticTitle(false)				.setCellBorder(Border.THIN)				.addColumn("State", "state", String.class.getName(), false)				.addRow("City", "city", String.class.getName(),false)				.addMeasure("amount", String.class.getName(),						DJCalculation.NOTHING, "Amount", new Style())				.setCellDimension(17, 60)				.setColumnHeaderHeight(30)				.setRowHeaderWidth(80)				.build();		drb.addHeaderCrosstab(djcross);		DynamicReport dr = drb.build();		// put a collection in the parameters map to be used by the crosstab		Map<String, Object> reportParams = new HashMap<String, Object>();		reportParams.put("sr", getTestDataLazyList());		// set a swap file virtualizer		JRSwapFile swapFile = new JRSwapFile(TMP_DIR_PATH, 1024, 10);		JRVirtualizer virtualizer = new JRSwapFileVirtualizer(1024, swapFile, true);		reportParams.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);		// generates jasper report		JasperReport jasperReport = DynamicJasperHelper.generateJasperReport(dr,			new ClassicLayoutManager(), reportParams);		// fills report and generates jasperprint		JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport,			reportParams, new JREmptyDataSource());		// export to pdf bytes		return JasperExportManager.exportReportToPdf(jasperPrint);	}	/**	 * returns test data.	 * @return test data	 */	private QueryLazyList getTestDataLazyList() {		return new QueryLazyList(1000);	}	public static void main(String[] args) throws JRException {		byte[] result = new ReportServiceImpl().generateCrossTabReport();		System.out.println(result.length);	}}
Link to comment
Share on other sites

AbstractLazyList.java

Code:
package model;import java.util.AbstractList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * Lazy list to a generic type. */public abstract class AbstractLazyList<T> extends AbstractList<T> {	/**	 * Already loaded data.	 */	private final Map<Integer, T> loadedData;	/**	 * How much itens shoud be retrieved at a query.	 */	private final int pageSize;	/**	 * Constructor with page size.	 * @param pageSize page size	 */	public AbstractLazyList(int pageSize) {		super();		this.pageSize = pageSize;		this.loadedData = new HashMap<Integer, T>(pageSize);	}	@Override	public T get(int position) {		if (!loadedData.containsKey(position)) {			loadedData.clear();			List<T> results = queryPage(position, pageSize);			int index = position;			for (T item : results) {				loadedData.put(index, item);				index++;			}		}		return loadedData.get(position);	}	@Override	public int size() {		return getTotalQueryResultsSize();	}	/**	 * Queries the new page.	 * @param position initial position	 * @param pageSize page size	 * @return results from position to page size	 */	public abstract List<T> queryPage(int position, int pageSize);	/**	 * Returns the total results returned by the query.	 * @return total number of results	 */	public abstract int getTotalQueryResultsSize();}
Link to comment
Share on other sites

QueryLazyList.java

Code:
/** * */package model; import java.util.ArrayList;import java.util.List; /** * Test implementation for a lazy list. */public class QueryLazyList extends AbstractLazyList<CrossTabDataVO> {    /**     * Total number of results.     */    int totalNumberResults = Integer.MAX_VALUE;     public QueryLazyList(int pageSize) {        super(pageSize);    }     @Override    public int getTotalQueryResultsSize() {        return totalNumberResults;    }     @Override    public List<CrossTabDataVO> queryPage(int position, int pageSize) {        List<CrossTabDataVO> resultsPage = new ArrayList<CrossTabDataVO>(pageSize);        for(int i = position; i < position + pageSize; i++) {            CrossTabDataVO crossTabDataVO = new CrossTabDataVO();            crossTabDataVO.setState("State " + i);            crossTabDataVO.setCity("City " + i);            crossTabDataVO.setAmount(i + ",00");            resultsPage.add(crossTabDataVO);        }        return resultsPage;    }}
Link to comment
Share on other sites

CrossTabDataVO.java

Code:
package model; import java.io.Serializable; /** * Data to be used inside crosstab. */public class CrossTabDataVO implements Serializable {     /** serial. */    private static final long serialVersionUID = 3785582945804552430L;     private String state;     private String city;     private String amount;     public String getState() {        return state;    }     public void setState(String state) {        this.state = state;    }     public String getCity() {        return city;    }     public void setCity(String city) {        this.city = city;    }     public String getAmount() {        return amount;    }     public void setAmount(String amount) {        this.amount = amount;    }}
Link to comment
Share on other sites

Crosstabs were meant to present concise aggregated data.  The aggregation is performed in-memory, and it is scalable wrt large data volumes as long as the data falls into a small number of buckets.

Therefore crosstabs do not suit the case of creating large tables.  What exactly do you want to display in your crosstab?

Regards,

Lucian

Link to comment
Share on other sites

In my case, i'm dealing with large tables.

I used crosstabs because it deals well with dynamic columns and when theses columns gets larger than the page width.

 

Can I design a report so that its columns are dynamic and jasper will deal automatically with column breaks?

 

Thanks for helping

Link to comment
Share on other sites

marciopd
Wrote:

In my case, i'm dealing with large tables.
I used crosstabs because it deals well with dynamic columns and when theses columns gets larger than the page width.

Can I design a report so that its columns are dynamic and jasper will deal automatically with column breaks?

Thanks for helping

Follow-up at http://jasperforge.org/plugins/espforum/view.php?group_id=102&forumid=103&topicid=77084

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...