great optimization in ForkParser
MODIFY
CHANGES.txt
CHANGES.txt
@@ -13,7 +13,11 @@ Release 2.0.0 - ???
Other changes
-Release 1.25 - 11/23/2020
+Release 1.26 - ???
+
+ * Great optimization in ForkParser (TIKA-3237).
+
+Release 1.25 - 11/25/2020
* Fix inconsistent license in xmpcore (TIKA-3204).

MODIFY
tika-core/src/main/java/org/apache/tika/fork/ContentHandlerProxy.java
tika-core/src/main/java/org/apache/tika/fork/ContentHandlerProxy.java
@@ -67,7 +67,7 @@ class ContentHandlerProxy implements ContentHandler, ForkProxy {
try {
if (string != null) {
output.writeBoolean(true);
- output.writeUTF(string);
+ writeString(string);
} else {
output.writeBoolean(false);
}
@@ -76,13 +76,26 @@ class ContentHandlerProxy implements ContentHandler, ForkProxy {
}
}
+ /**
+ * Breaks the string in 21,845 size chunks to not throw UTFDataFormatException at least in Oracle JDK 8.
+ */
+ private void writeString(String string) throws IOException {
+ int max = 65535 / 3;
+ int frags = (int) Math.ceil((double) string.length() / max);
+ output.writeInt(frags);
+ int i = 0;
+ while (i < frags) {
+ int end = (i < frags - 1) ? (i + 1) * max : string.length();
+ output.writeUTF(string.substring(i * max, end));
+ i++;
+ }
+ }
+
private void sendCharacters(char[] ch, int start, int length)
throws SAXException {
try {
- output.writeInt(length);
- for (int i = 0; i < length; i++) {
- output.writeChar(ch[start + i]);
- }
+ writeString(new String(ch, start, length));
+
} catch (IOException e) {
throw new SAXException("Unexpected fork proxy problem", e);
}

MODIFY
tika-core/src/main/java/org/apache/tika/fork/ContentHandlerResource.java
tika-core/src/main/java/org/apache/tika/fork/ContentHandlerResource.java
@@ -89,19 +89,23 @@ class ContentHandlerResource implements ForkResource {
private String readString(DataInputStream input) throws IOException {
if (input.readBoolean()) {
- return input.readUTF();
+ return readStringUTF(input);
} else {
return null;
}
}
private char[] readCharacters(DataInputStream input) throws IOException {
- int n = input.readInt();
- char[] ch = new char[n];
- for (int i = 0; i < n; i++) {
- ch[i] = input.readChar();
+ return readStringUTF(input).toCharArray();
+ }
+
+ private String readStringUTF(DataInputStream input) throws IOException {
+ int frags = input.readInt();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < frags; i++) {
+ sb.append(input.readUTF());
}
- return ch;
+ return sb.toString();
}
}

MODIFY
tika-core/src/test/java/org/apache/tika/fork/ForkParserTest.java
tika-core/src/test/java/org/apache/tika/fork/ForkParserTest.java
@@ -21,6 +21,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -413,6 +415,18 @@ public class ForkParserTest extends TikaTest {
assertEquals("/embed1.xml", m1.get(RecursiveParserWrapperHandler.EMBEDDED_RESOURCE_PATH));
}
+ @Test
+ public void testNoUTFDataFormatException() throws Exception {
+ ContentHandlerProxy proxy = new ContentHandlerProxy(0);
+ DataOutputStream output = new DataOutputStream(new ByteArrayOutputStream());
+ proxy.init(null, output);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 65536; i++) {
+ sb.append(1);
+ }
+ proxy.skippedEntity(sb.toString());
+ }
+
//use this to test that the wrapper handler is acted upon by the server but not proxied back
private static class ToFileHandler extends AbstractRecursiveParserWrapperHandler {

TIKA-3237: great optimization in ForkParser