Bug 59806 - CTBarChart org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException
Summary: CTBarChart org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException
Status: RESOLVED DUPLICATE of bug 60102
Alias: None
Product: POI
Classification: Unclassified
Component: XSLF (show other bugs)
Version: 3.14-FINAL
Hardware: PC Windows NT
: P2 enhancement (vote)
Target Milestone: ---
Assignee: POI Developers List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-07-06 08:12 UTC by dengyf
Modified: 2018-02-10 14:48 UTC (History)
0 users



Attachments
CTBarChar use ooxml-schemas-1.1.jar (83.54 KB, application/vnd.openxmlformats-officedocument.presentationml.presentation)
2016-07-06 08:12 UTC, dengyf
Details
simplified unit test (4.91 KB, patch)
2016-07-06 10:30 UTC, Javen O'Neal
Details | Diff
simplified unit test (2.97 KB, patch)
2016-07-06 10:33 UTC, Javen O'Neal
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
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)

////////////////////////////////////////////
program

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) {
		    e.printStackTrace();
	    }
    }

	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));  
	            //获取第一个ppt页面  
	          //  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;  
	                    break;  
	                }  
	            }  
	            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();
				tx.getStrRef().getStrCache().getPtArray(0).setV(newChartTitle);
				sheet.createRow(0).createCell(1).setCellValue(newChartTitle);
				String titleRef = new CellReference(sheet.getSheetName(), 0, 1, true, true).formatAsString();
				tx.getStrRef().setF(titleRef);

				// 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();
					numVal.setIdx(idx);
					numVal.setV(value);

					CTStrVal sVal = strData.addNewPt();
					sVal.setIdx(idx);
					sVal.setV(key);

					idx++;
					XSSFRow row = sheet.createRow(rownum++);
					row.createCell(0).setCellValue(key);
					row.createCell(1).setCellValue(Double.valueOf(value));
				}
				numData.getPtCount().setVal(idx);
				strData.getPtCount().setVal(idx);

				String numDataRange = new CellRangeAddress(1, rownum - 1, 1, 1).formatAsString(sheet.getSheetName(), true);
				val.getNumRef().setF(numDataRange);
				String axisDataRange = new CellRangeAddress(1, rownum - 1, 0, 0).formatAsString(sheet.getSheetName(), true);
				cat.getStrRef().setF(axisDataRange);

				// updated the embedded workbook with the data
				xlsOut = xlsPart.getPackagePart().getOutputStream();
				try {
					wb.write(xlsOut);
				} finally {
					xlsOut.close();
				}
				FileOutputStream fos = new FileOutputStream(outputPath);
				try {
					pptx.write(fos);
				} finally {
					fos.close();
				}
			} finally {
				wb.close();
			}
		} 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)) {
						break;
					} 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?

https://poi.apache.org/faq.html#faq-N10025
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 ***