Bug 59806

Summary: CTBarChart org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException
Product: POI Reporter: dengyf <yongfeid>
Component: XSLFAssignee: POI Developers List <dev>
Severity: enhancement    
Priority: P2    
Version: 3.14-FINAL   
Target Milestone: ---   
Hardware: PC   
OS: Windows NT   
Attachments: CTBarChar use ooxml-schemas-1.1.jar
simplified unit test
simplified unit test

Description dengyf 2016-07-06 08:12:35 UTC
Created attachment 34014 [details]
CTBarChar  use ooxml-schemas-1.1.jar

Exception in thread "main" org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException: Rule M2.4 exception : this error should NEVER happen! Please raise a bug at https://bz.apache.org/bugzilla/enter_bug.cgi?product=POI and attach a file that triggers it, thanks!
	at org.apache.poi.openxml4j.opc.internal.ContentTypeManager.getContentType(ContentTypeManager.java:343)
	at org.apache.poi.openxml4j.opc.internal.ContentTypeManager.removeContentType(ContentTypeManager.java:256)
	at org.apache.poi.openxml4j.opc.OPCPackage.removePart(OPCPackage.java:958)
	at org.apache.poi.openxml4j.opc.PackagePart.getOutputStream(PackagePart.java:522)
	at ExcelWritingbug.updateBarChartTemplate(ExcelWritingbug.java:131)
	at ExcelWritingbug.main(ExcelWritingbug.java:36)


import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFChart;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

public class ExcelWritingbug {

    public static void main(String[] args) {
	    String inputPath = "e:\\excel_writing_bug.pptx";
	    String outputPath = "e:\\excel_writing_bug_output.pptx";
	    int slideNumber = 1;
	    String templateChartTitle = "Title";
	    String newChartTitle = "Title updated";
	    Map<String, Double> chartValues = new HashMap<String, Double>();
	    chartValues.put("Windows", 5d);
	    chartValues.put("Solaris", 2d);
	    chartValues.put("Unix", 8d);
	    chartValues.put("Linux", 5d);
	    try {
		    updateBarChartTemplate(inputPath, outputPath, slideNumber, templateChartTitle, newChartTitle, chartValues);
	    } catch (IOException e) {

	public static void updateBarChartTemplate(String inputPath, String outputPath, int slideNumber, String templateChartTitle, String newChartTitle, Map<String, Double> chartValues)
		throws IllegalStateException, IOException{

		XMLSlideShow pptx = null;
		try {
			 pptx = new XMLSlideShow(new FileInputStream(inputPath));  
	          //  XSLFSlide slide = pptx.getSlides().get(0);  
			//pptx = new XMLSlideShow(new FileInputStream(inputPath));
	            XSLFChart chart = null;  
	            for(POIXMLDocumentPart part : slide.getRelations()){  
	                if(part instanceof XSLFChart){  
	                    chart = (XSLFChart) part;  
	            if (chart == null) {  
	                return "no chart";  
	            POIXMLDocumentPart xlsPart = chart.getRelations().get(0);  
			XSLFChart chart = getChartFromTitle(inputPath, slideNumber, templateChartTitle);
			if (chart == null) throw new IllegalStateException("chart not found in the template");
			// embedded Excel workbook that holds the chart data
			POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
			XSSFWorkbook wb = new XSSFWorkbook();
			OutputStream xlsOut = null;
			try {
				XSSFSheet sheet = wb.createSheet();

				CTChart ctChart = chart.getCTChart();

				CTPlotArea plotArea = ctChart.getPlotArea();

				CTBarChart barChart = plotArea.getBarChartArray(0);
				//Bar Chart Series
				CTBarSer ser = barChart.getSerArray(0);

				// Series Text
				CTSerTx tx = ser.getTx();
				String titleRef = new CellReference(sheet.getSheetName(), 0, 1, true, true).formatAsString();

				// Category Axis Data
				CTAxDataSource cat = ser.getCat();
				CTStrData strData = cat.getStrRef().getStrCache();

				// Values
				CTNumDataSource val = ser.getVal();
				CTNumData numData = val.getNumRef().getNumCache();

				strData.setPtArray(null);  // unset old axis text
				numData.setPtArray(null);  // unset old values

				// set model
				int idx = 0;
				int rownum = 1;

				for (Map.Entry<String, Double> entry : chartValues.entrySet()) {
					String key = entry.getKey();
					String value = String.valueOf(entry.getValue());
					CTNumVal numVal = numData.addNewPt();

					CTStrVal sVal = strData.addNewPt();

					XSSFRow row = sheet.createRow(rownum++);

				String numDataRange = new CellRangeAddress(1, rownum - 1, 1, 1).formatAsString(sheet.getSheetName(), true);
				String axisDataRange = new CellRangeAddress(1, rownum - 1, 0, 0).formatAsString(sheet.getSheetName(), true);

				// updated the embedded workbook with the data
				xlsOut = xlsPart.getPackagePart().getOutputStream();
				try {
				} finally {
				FileOutputStream fos = new FileOutputStream(outputPath);
				try {
				} finally {
			} finally {
		} finally {
			if (pptx != null) pptx.close();

	public static XSLFChart getChartFromTitle(String inputPath, int slideNumber, String templateChartTitle) throws IOException {
		XMLSlideShow pptx = null;
		try {
			pptx = new XMLSlideShow(new FileInputStream(inputPath));

			XSLFSlide slide = pptx.getSlides().get(slideNumber - 1);
			// find chart in the slide
			XSLFChart chart = null;
			for (POIXMLDocumentPart part : slide.getRelations()) {
				if (part instanceof XSLFChart) {
					chart = (XSLFChart) part;
					CTChart ctChart = chart.getCTChart();

					CTTitle ctTitle = ctChart.getTitle();
					CTTx titleTx = ctTitle.getTx();
					CTTextBody body = titleTx.getRich();
					CTTextParagraph paragraph = body.getPArray(0);
					String chartTitle = paragraph.getRArray(0).getT();

					if (chartTitle.equalsIgnoreCase(templateChartTitle)) {
					} else {
						chart = null;
			return chart;
		} finally {
			if (pptx != null) pptx.close();
Comment 1 Javen O'Neal 2016-07-06 09:34:06 UTC
What version of POI are you using?

Could you try this again with ooxml-schemas-1.3, making sure to delete any duplicate ooxml-schemas and poi-ooxml-schemas on your classpath?

Comment 2 Javen O'Neal 2016-07-06 10:30:43 UTC
Created attachment 34015 [details]
simplified unit test

I cut your example down to the attached unit test.

The source of the problem is in getChartFromTitle. You're opening the slideshow, creating an XSLFChart object, and closing the slideshow. Then you're passing the XSLFChart object that belongs to the closed slideshow back to updateBarChartTemplate.

Naturally, once you've closed a resource, any subsequent operations performed on that resource are likely to fail.

Perhaps we could give a more informative error message here, like "could not access package part output stream because the underlying document has been closed.
Comment 3 Javen O'Neal 2016-07-06 10:33:04 UTC
Created attachment 34016 [details]
simplified unit test
Comment 4 Dominik Stadler 2016-07-15 18:46:56 UTC
Set to enhancement as original problem is explained by closing the Slideshow too early and only some improved error reporting is remaining to be done.
Comment 5 Alain Fagot Bearez 2018-02-10 14:48:21 UTC

*** This bug has been marked as a duplicate of bug 60102 ***