Hi,
I am interested to know if there is an idiomatic way to avoid or recover
from crashes in the following use case.
The program opens an OpenOffice writer document with a custom XInputStream
defined below.
It changes some user fields and bookmarks contents and save the document as
pdf.
For saving it uses the XStorable.storeUrl method and a custom XOutputStream,
also defined below.
When doing the stress test below, it always crashes after having looped
around 8500 times with the exception:
com.sun.star.lang.IllegalArgumentException: URL seems to be an unsupported
one
I have put a comment on the code above the line where the program itself
crashes.
The OpenOffice instance is still up and running though.
1- Is there something wrong in the code that causes the crash? Maybe some
wrong parameter?
Something else that needs to be closed or disposed?
2- If not is there a proper way to recover from the crash and retry the
operation?
What are usually the recoverable exceptions and which cleanup should be
done? Maybe we need to reload / refresh / recreate some object for a safe
recovery?
Any idea?
PS.: I find the "URL seems to be an unsupported one" message quite puzzling
since the URL that is used is always "private:stream".
So why do this URL become unsupported after it has been used for about 8500
times?
// MAIN Java code
final XComponentContext context = Bootstrap
.createInitialComponentContext(null);
final XUnoUrlResolver resolver = UnoUrlResolver.create(context);
final String unoUrl =
"uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager";
final Object initialObject = resolver.resolve(unoUrl);
final XMultiComponentFactory factory = (XMultiComponentFactory) UnoRuntime
.queryInterface(XMultiComponentFactory.class, initialObject);
final XPropertySet props = (XPropertySet) UnoRuntime.queryInterface(
XPropertySet.class, factory);
final Object defaultContext = props.getPropertyValue("DefaultContext");
final XComponentContext componentContent = (XComponentContext) UnoRuntime
.queryInterface(XComponentContext.class, defaultContext);
final Object frameDesktop = factory.createInstanceWithContext(
"com.sun.star.frame.Desktop", componentContent);
final XDesktop desktop = (XDesktop) UnoRuntime.queryInterface(
XDesktop.class, frameDesktop);
final XComponentLoader loader = (XComponentLoader) UnoRuntime
.queryInterface(XComponentLoader.class, desktop);
for (int i = 0; i < 20000; i++) {
final OfficeInputStream officeInputStream = new OfficeInputStream(
new FileInputStream("some-path.odt"));
final PropertyValue[] propsVals = new PropertyValue[2];
propsVals[0] = new PropertyValue();
propsVals[0].Name = "InputStream";
propsVals[0].Value = officeInputStream;
propsVals[1] = new PropertyValue();
propsVals[1].Name = "Hidden";
propsVals[1].Value = Boolean.TRUE;
// IT CRASHES WHEN EXECUTING THE LINE BELOW
final XComponent doc = loader.loadComponentFromURL(
"private:stream", "doc", 0, propsVals);
officeInputStream.closeInput();
// DO SOME STUFF WITH DOC :
// change content of user fields and bookmarks, refresh
// and save as pdf
// ...
doc.dispose();
}
// THE OFFICEINPUTSTREAM CLASS
final class OfficeInputStream extends ByteArrayInputStream implements
XSeekable, XInputStream {
OfficeInputStream(final byte[] buf) {
super(buf);
}
OfficeInputStream(final InputStream input) throws java.io.IOException {
this(IOUtils.toByteArray(input));
}
public int readBytes(final byte[][] buffer, final int bufferSize)
throws NotConnectedException, BufferSizeExceededException,
com.sun.star.io.IOException {
int numberOfReadBytes;
try {
byte[] bytes = new byte[bufferSize];
numberOfReadBytes = super.read(bytes);
if (numberOfReadBytes > 0) {
if (numberOfReadBytes < bufferSize) {
final byte[] smallerBuffer = new
byte[numberOfReadBytes];
System.arraycopy(bytes, 0, smallerBuffer, 0,
numberOfReadBytes);
bytes = smallerBuffer;
}
} else {
bytes = new byte[0];
numberOfReadBytes = 0;
}
buffer[0] = bytes;
return numberOfReadBytes;
} catch (final java.io.IOException e) {
throw new IOException(e.getMessage(), this);
}
}
public int readSomeBytes(final byte[][] buffer, final int bufferSize)
throws NotConnectedException, BufferSizeExceededException,
IOException {
return readBytes(buffer, bufferSize);
}
public void skipBytes(final int skipLength) throws
NotConnectedException,
BufferSizeExceededException, IOException {
skip(skipLength);
}
public void closeInput() throws NotConnectedException,
com.sun.star.io.IOException {
try {
close();
} catch (final java.io.IOException e) {
throw new IOException(e.getMessage(), this);
}
}
public long getLength() throws IOException {
return count;
}
public long getPosition() throws IOException {
return pos;
}
public void seek(final long position) throws IllegalArgumentException,
IOException {
pos = (int) position;
}
}
// THE OFFICEOUTPUTSTREAM CLASS
final class OfficeOutputStream extends ByteArrayOutputStream implements
XOutputStream {
private static final int BUFFER_SIZE = 32768;
OfficeOutputStream() {
super(BUFFER_SIZE);
}
public void writeBytes(final byte[] values) throws
NotConnectedException,
BufferSizeExceededException, IOException {
try {
this.write(values);
} catch (final java.io.IOException e) {
throw new IOException(e.getMessage());
}
}
public void closeOutput() throws NotConnectedException,
BufferSizeExceededException, com.sun.star.io.IOException {
try {
super.flush();
super.close();
} catch (final java.io.IOException e) {
throw new IOException(e.getMessage());
}
}
@Override
public void flush() {
try {
super.flush();
} catch (final java.io.IOException e) {
}
}
}