Merging multiple word documents (with images) in Java - apache-poi

I am trying to create a simple utility application but have issues with merging two word documents with images.
Pls find my below code (i am using Apache POI). The code works fine for Text and other information but fails to merge documents with Images.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
public class WordMerge {
private final OutputStream result;
private final List<InputStream> inputs;
private XWPFDocument first;
public WordMerge(OutputStream result) {
this.result = result;
inputs = new ArrayList<>();
}
public void add(InputStream stream) throws Exception{
inputs.add(stream);
OPCPackage srcPackage = OPCPackage.open(stream);
XWPFDocument src1Document = new XWPFDocument(srcPackage);
if(inputs.size() == 1){
first = src1Document;
} else {
CTBody srcBody = src1Document.getDocument().getBody();
first.getDocument().addNewBody().set(srcBody);
}
}
public void doMerge() throws Exception{
first.write(result);
}
public void close() throws Exception{
result.flush();
result.close();
for (InputStream input : inputs) {
input.close();
}
}
public static void main(String[] args) throws Exception {
FileOutputStream faos = new FileOutputStream("C:/temp/result.docx");
WordMerge wm = new WordMerge(faos);
wm.add( new FileInputStream("C:\\temp\\test.docx") );
wm.add( new FileInputStream("C:\\temp\\word_images.docx") );
wm.doMerge();
wm.close();
}
}

Related

Error org.picocontainer.PicoCompositionException: Duplicate Keys not allowed. Duplicate

I was trying to achieve, Cucumber feature level parallel execution using pico Container.
When I am using a shared Driver in a context Class as below, I get org.picocontainer.PicoCompositionException: Duplicate Keys not allowed. Duplicate
public class Context{
private ThreadLocal<WebDriver> drivers = new ThreadLocal<>();
public void setDriver(WebDriver wd) {
drivers.set(wd);
}
public WebDriver getDriver() {
return drivers.get();
}
//Runner Class
import java.net.MalformedURLException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.CucumberFeatureWrapper;
import cucumber.api.testng.TestNGCucumberRunner;
import net.thumbtack.cucumber.picocontainer.example.step.SharedDriver;
import cucumber.api.testng.*;
#CucumberOptions (glue = {"net.thumbtack.cucumber.picocontainer.example.step"},
features = "src/main/resources/"
,tags = {"#Scenario2,#Scenario3"})
public class TestRunner {
public TestRunner() throws MalformedURLException {
super();
// TODO Auto-generated constructor stub
}
private TestNGCucumberRunner testNGCucumberRunner;
#BeforeClass(alwaysRun = true)
public void setUpClass() throws Exception {
testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
System.setProperty("ExecEnv","Docker");
}
// #Test(dataProvider = "features")
// public void feature(PickleEventWrapper eventwrapper,CucumberFeatureWrapper cucumberFeature) throws Throwable {
#Test(groups="cucumber", description="Runs CucumberFeature",dataProvider = "features")
public void feature(CucumberFeatureWrapper cucumberFeature){
testNGCucumberRunner.runCucumber(cucumberFeature.getCucumberFeature());
// testNGCucumberRunner.runScenario(eventwrapper.getPickleEvent());
}
#DataProvider(parallel=true)
public Object[][] features() {
return testNGCucumberRunner.provideFeatures();
// return testNGCucumberRunner.provideScenarios();
}
#AfterClass(alwaysRun = true)
public void tearDownClass() throws Exception {
testNGCucumberRunner.finish();
}
}

How to renames the slide master

I want rename the PowerPoint slide master by apache poi. In PowerPoint GUI we do View - Slide Master - then we right click the top most slide on left side and select Rename Master from context menu.
In a PowerPoint presentation the master is named such as it's theme. We can get all masters using XMLSlideShow.getSlideMasters. XSLFSlideMaster
extends XSLFSheet. So we can get the theme of each master using XSLFSheet.getTheme. Once we have the XSLFTheme there are getters and setters for the name.
Example:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xslf.usermodel.*;
public class XSLFRenameMasterTheme {
public static void main(String[] args) throws Exception {
XMLSlideShow slideshow = new XMLSlideShow(new FileInputStream("Presentation.pptx"));
for (XSLFSlideMaster master : slideshow.getSlideMasters()) {
XSLFTheme theme = master.getTheme();
String name = theme.getName();
System.out.println(name);
theme.setName(name + " renamed");
System.out.println(theme.getName());
}
FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.pptx");
slideshow.write(out);
out.close();
slideshow.close();
}
}
For HSLFSlideShow is seems there is no access to master names supported. One can get the HSLFSlideMasters but not the names of them.
So if one needs doing that nevertheless, then one must know about the internals of the binary *.ppt file system. This is documented in [MS-PPT]: PowerPoint (.ppt) Binary File Format. The sheet names are in a SlideNameAtom. With knowledge about the internals one can create a class for that kind of record. This can providing methods for get and set the name then.
Example:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordAtom;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
public class HSLFRenameMaster {
// method for get SlideNameAtom out of the master
private static SlideNameAtom getSlideNameAtom(HSLFSlideMaster master) throws Exception {
SlideNameAtom slideNameAtomRecord = null;
Record record = master.getSheetContainer().findFirstOfType(0x0FBA);
if (record != null) { // SlideNameAtom exists
// get present data
ByteArrayOutputStream out = new ByteArrayOutputStream();
record.writeOut(out);
out.flush();
byte[] data = out.toByteArray();
out.close();
// create new SlideNameAtom from data
slideNameAtomRecord = new SlideNameAtom(data);
// replace old record with new SlideNameAtom
master.getSheetContainer().addChildBefore(
slideNameAtomRecord,
record
);
master.getSheetContainer().removeChild(record);
}
return slideNameAtomRecord;
}
public static void main(String[] args) throws Exception {
HSLFSlideShow slideshow = new HSLFSlideShow(new FileInputStream("Presentation.ppt"));
for (HSLFSlideMaster master : slideshow.getSlideMasters()) {
SlideNameAtom slideNameAtomRecord = getSlideNameAtom(master);
if (slideNameAtomRecord != null) {
String name = slideNameAtomRecord.getName();
System.out.println(name);
slideNameAtomRecord.setName(name + " renamed");
System.out.println(slideNameAtomRecord.getName());
}
}
FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.ppt");
slideshow.write(out);
out.close();
slideshow.close();
}
//class SlideNameAtom
//having methods for manipulating the [SlideNameAtom](https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx)
private static class SlideNameAtom extends RecordAtom {
private byte[] data;
private String name;
public SlideNameAtom() {
this.name = "Office";
setName(name);
}
public SlideNameAtom(byte[] data) {
this.data = data;
this.name = getName();
}
public void setName(String name) {
this.name = name;
int length = 8;
length += StringUtil.getToUnicodeLE(name).length;
this.data = new byte[length];
data[0] = (byte)0x20; data[1] = (byte)0x00;
data[2] = (byte)0xBA; data[3] = (byte)0x0F; //MUST be 0x0fba = RT_CString (little endian)
LittleEndian.putInt(data, 4, StringUtil.getToUnicodeLE(name).length);
StringUtil.putUnicodeLE(name, data, 8);
}
public String getName() {
return StringUtil.getFromUnicodeLE(this.data, 8, (this.data.length-8)/2);
}
#Override
public void writeOut(OutputStream out) throws IOException {
out.write(data);
}
#Override
public long getRecordType() { return 0x0FBA; }
}
}
The question is whether renaming the master is worth that effort.

how to validate an xml string in java?

I have seen some examples here, which show how to validate an xml File (It´s workking), but my question is: How can I modify this code to validate an String
import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.util.List;
import java.io.*;
import java.util.LinkedList;
import java.net.URL;
import java.sql.Clob;
import java.sql.SQLException;
public class Validate {
public String validaXML(){
try {
Source xmlFile = new StreamSource(new File("C:\\Users\\Desktop\\info.xml"));
URL schemaFile = new URL("https://www.w3.org/2001/XMLSchema.xsd");
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
final List exceptions = new LinkedList();
validator.setErrorHandler(new ErrorHandler()
{
#Override
public void warning(SAXParseException exception) throws SAXException
{
exceptions.add(exception);
}
#Override
public void fatalError(SAXParseException exception) throws SAXException
{
exceptions.add(exception);
}
#Override
public void error(SAXParseException exception) throws SAXException
{
exceptions.add(exception);
}
});
validator.validate(xmlFile);
} catch (SAXException ex) {
System.out.println( ex.getMessage());
return ex.getMessage().toString();
} catch (IOException e) {
System.out.println( e.getMessage());
return e.getMessage().toString();
}
return "Valid";
}
public static void main(String[] args) {
String res;
Validate val = new Validate();
res=val.validaXML();
System.out.println(res);
}
}
I have tried with this:
Source xmlFile = new StreamSource("<Project><Name>sample</Name></Project>");
It compiles, but I got this:
"no protocol: sample"
Thanks for reading I´ll apreciate you opinion
The reason why that doesnt work is the constructor your using is StreamSource(String systemId). The String constructor on StreamSource doesnt take xml.
Use the constructor StreamSource(Reader reader) and make an reader, such as
new StreamSource(new StringReader("xml here"))
or you can use the constructor StreamSource(InputStream inputStream) as
new StreamSource(new ByteArrayInputStream("xml here".getBytes()))

apache poi---How to read password protected .doc file using java code?

How to read password protected .doc file using java code??
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
public class MsFileReader
{
public static void readDocFile(String fileName)
{
try
{
File file = new File(fileName);
InputStream fis = new FileInputStream(file);
HWPFDocument doc = new HWPFDocument(fis);
WordExtractor we = new WordExtractor(doc);
String[] paragraphs = we.getParagraphText();
System.out.println("Total no of paragraph "+paragraphs.length);
for (String para : paragraphs)
{
System.out.println(para.toString());
}
fis.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
//Test.doc is password encrypted file
//after running this code it throws exception
//EncryptedDocumentException
readDocFile("C:\\Test.doc");
}
}
I want java code to read password encrypted .doc file.
I get EncryptedDocumentException at HWPFDocument doc = new HWPFDocument(fis);

Update JavaFX 2 GUI at intervals?

I've spent like the last 24 hours trying to learn JavaFX. I'm trying to build a GUI that will display values from a data source (for example a database). My question is what the preferred way is to do this. So far I've come up with this code to build a simple GUI and get some data from a data source:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class AvcHmi extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Text t = new Text(10, 50, "Replace/update this text periodically with data");
Group root = new Group();
root.getChildren().add(t);
primaryStage.setScene(new Scene(root, 400, 300));
primaryStage.show();
new Thread() {
private DataSource dataSource = new DataSource();
{ setDaemon(true); }
#Override
public void run() {
try {
for(;;) {
Thread.sleep(100);
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println(dataSource.getDataMap().get("key1"));
}});
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
Datasource:
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class DataSource {
Map<String,String> dataMap = new HashMap<>();
public DataSource() {
dataMap.put("key1", "value1");
dataMap.put("key2", "value2");
dataMap.put("key3", "value3");
}
public Map<String, String> getDataMap() {
Random generator = new Random();
int randInt = generator.nextInt();
dataMap.put("key1", "value"+randInt);
return dataMap;
}
}
100 ms is OK interval to update this GUI as far as I'm concerned. But is this a viable solution?
The next step is to replace the text with a value from the data source. Been looking at Collections and ObservableMap and wondering if it's a preferred way of doing the actual GUI updates? I'm aving some problems with inner classes and final variables but might reason that out after some sleep.
Also, the target machine is not that powerful (somewhere between 350-512 mb RAM). Could this be an issue? My simple tests so far seems to run fine.
Thank you for any feedback on this.
This Oracle example shows how to achieve concurrency loading in data table, with source code; it might help you
You could also look at reading about javafx.concurrent.Task<V> API.
The code on the Oracle example is as follows:
public class UpdateCustomerTask extends Task<Customer> {
private final Customer customer;
public UpdateCustomerTask(Customer customer) {
this.customer = customer;
}
#Override protected Customer call() throws Exception {
// pseudo-code:
// query the database
// read the values
// Now update the customer
Platform.runLater(new Runnable() {
#Override public void run() {
customer.setF setFirstName(rs.getString("FirstName"));
// etc
}
});
return customer;
}
}

Resources