You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tika.apache.org by ju...@apache.org on 2011/01/21 15:59:18 UTC
svn commit: r1061834 - in
/tika/trunk/tika-core/src/main/java/org/apache/tika/fork: ForkClient.java
ForkObjectInputStream.java ForkParser.java ForkServer.java
Author: jukka
Date: Fri Jan 21 14:59:18 2011
New Revision: 1061834
URL: http://svn.apache.org/viewvc?rev=1061834&view=rev
Log:
TIKA-416: Out-of-process text extraction
Add better error handling to forked processes
Modified:
tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkClient.java
tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkObjectInputStream.java
tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkParser.java
tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkServer.java
Modified: tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkClient.java
URL: http://svn.apache.org/viewvc/tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkClient.java?rev=1061834&r1=1061833&r2=1061834&view=diff
==============================================================================
--- tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkClient.java (original)
+++ tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkClient.java Fri Jan 21 14:59:18 2011
@@ -16,14 +16,12 @@
*/
package org.apache.tika.fork;
-import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -31,6 +29,7 @@ import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
+import org.apache.tika.io.IOExceptionWithCause;
import org.apache.tika.io.IOUtils;
import org.xml.sax.ContentHandler;
@@ -38,6 +37,8 @@ class ForkClient {
private final List<ForkResource> resources = new ArrayList<ForkResource>();
+ private final ClassLoader loader;
+
private final File jar;
private final Process process;
@@ -52,6 +53,7 @@ class ForkClient {
throws IOException {
boolean ok = false;
try {
+ this.loader = loader;
this.jar = createBootstrapJar();
ProcessBuilder builder = new ProcessBuilder();
@@ -77,7 +79,7 @@ class ForkClient {
}
}
- public synchronized void call(String method, Object... args)
+ public synchronized Throwable call(String method, Object... args)
throws IOException {
List<ForkResource> r = new ArrayList<ForkResource>(resources);
output.writeByte(ForkServer.CALL);
@@ -85,7 +87,7 @@ class ForkClient {
for (int i = 0; i < args.length; i++) {
sendObject(args[i], r);
}
- waitForResponse(r);
+ return waitForResponse(r);
}
/**
@@ -110,14 +112,7 @@ class ForkClient {
object = new ClassLoaderProxy(n);
}
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ObjectOutputStream serializer = new ObjectOutputStream(buffer);
- serializer.writeObject(object);
- serializer.close();
-
- byte[] data = buffer.toByteArray();
- output.writeInt(data.length);
- output.write(data);
+ ForkObjectInputStream.sendObject(object, output);
waitForResponse(resources);
}
@@ -143,7 +138,7 @@ class ForkClient {
}
}
- private byte waitForResponse(List<ForkResource> resources)
+ private Throwable waitForResponse(List<ForkResource> resources)
throws IOException {
output.flush();
while (true) {
@@ -157,8 +152,16 @@ class ForkClient {
ForkResource resource =
resources.get(input.readUnsignedByte());
resource.process(input, output);
+ } else if (type == ForkServer.ERROR) {
+ try {
+ return (Throwable) ForkObjectInputStream.readObject(
+ input, loader);
+ } catch (ClassNotFoundException e) {
+ throw new IOExceptionWithCause(
+ "Unable to deserialize an exception", e);
+ }
} else {
- return (byte) type;
+ return null;
}
}
}
Modified: tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkObjectInputStream.java
URL: http://svn.apache.org/viewvc/tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkObjectInputStream.java?rev=1061834&r1=1061833&r2=1061834&view=diff
==============================================================================
--- tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkObjectInputStream.java (original)
+++ tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkObjectInputStream.java Fri Jan 21 14:59:18 2011
@@ -16,9 +16,14 @@
*/
package org.apache.tika.fork;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
/**
@@ -64,4 +69,45 @@ class ForkObjectInputStream extends Obje
return Class.forName(desc.getName(), false, loader);
}
+ /**
+ * Serializes the object first into an in-memory buffer and then
+ * writes it to the output stream with a preceding size integer.
+ *
+ * @param object object to be serialized
+ * @param output output stream
+ * @throws IOException if the object could not be serialized
+ */
+ public static void sendObject(Object object, DataOutputStream output)
+ throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ ObjectOutputStream serializer = new ObjectOutputStream(buffer);
+ serializer.writeObject(object);
+ serializer.close();
+
+ byte[] data = buffer.toByteArray();
+ output.writeInt(data.length);
+ output.write(data);
+ }
+
+ /**
+ * Deserializes an object from the given stream. The serialized object
+ * is expected to be preceded by a size integer, that is used for reading
+ * the entire serialization into a memory before deserializing it.
+ *
+ * @param input input stream from which the serialized object is read
+ * @param loader class loader to be used for loading referenced classes
+ * @throws IOException if the object could not be deserialized
+ * @throws ClassNotFoundException if a referenced class is not found
+ */
+ public static Object readObject(DataInputStream input, ClassLoader loader)
+ throws IOException, ClassNotFoundException {
+ int n = input.readInt();
+ byte[] data = new byte[n];
+ input.readFully(data);
+
+ ObjectInputStream deserializer =
+ new ForkObjectInputStream(new ByteArrayInputStream(data), loader);
+ return deserializer.readObject();
+ }
+
}
Modified: tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkParser.java
URL: http://svn.apache.org/viewvc/tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkParser.java?rev=1061834&r1=1061833&r2=1061834&view=diff
==============================================================================
--- tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkParser.java (original)
+++ tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkParser.java Fri Jan 21 14:59:18 2011
@@ -111,7 +111,18 @@ public class ForkParser implements Parse
throws IOException, SAXException, TikaException {
ForkClient client = acquireClient();
try {
- client.call("parse", stream, handler, metadata, context);
+ Throwable t = client.call(
+ "parse", stream, handler, metadata, context);
+ if (t instanceof IOException) {
+ throw (IOException) t;
+ } else if (t instanceof SAXException) {
+ throw (SAXException) t;
+ } else if (t instanceof TikaException) {
+ throw (TikaException) t;
+ } else if (t != null) {
+ throw new TikaException(
+ "Unexpected error in forked server process", t);
+ }
} finally {
releaseClient(client);
}
Modified: tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkServer.java
URL: http://svn.apache.org/viewvc/tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkServer.java?rev=1061834&r1=1061833&r2=1061834&view=diff
==============================================================================
--- tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkServer.java (original)
+++ tika/trunk/tika-core/src/main/java/org/apache/tika/fork/ForkServer.java Fri Jan 21 14:59:18 2011
@@ -21,8 +21,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.ObjectInputStream;
import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.zip.CheckedInputStream;
@@ -31,6 +31,8 @@ import java.util.zip.Checksum;
class ForkServer implements Runnable, Checksum {
+ public static final byte ERROR = -1;
+
public static final byte DONE = 0;
public static final byte CALL = 1;
@@ -109,18 +111,11 @@ class ForkServer implements Runnable, Ch
if (request == -1) {
break;
} else if (request == CALL) {
- Method method = getMethod(object, input.readUTF());
- Object[] args =
- new Object[method.getParameterTypes().length];
- for (int i = 0; i < args.length; i++) {
- args[i] = readObject(loader);
- }
- method.invoke(object, args);
- output.write(DONE);
- output.flush();
+ call(loader, object);
} else {
throw new IllegalStateException("Unexpected request");
}
+ output.flush();
}
} catch (Throwable t) {
t.printStackTrace();
@@ -128,6 +123,22 @@ class ForkServer implements Runnable, Ch
System.err.flush();
}
+ private void call(ClassLoader loader, Object object) throws Exception {
+ Method method = getMethod(object, input.readUTF());
+ Object[] args =
+ new Object[method.getParameterTypes().length];
+ for (int i = 0; i < args.length; i++) {
+ args[i] = readObject(loader);
+ }
+ try {
+ method.invoke(object, args);
+ output.write(DONE);
+ } catch (InvocationTargetException e) {
+ output.write(ERROR);
+ ForkObjectInputStream.sendObject(e.getCause(), output);
+ }
+ }
+
private Method getMethod(Object object, String name) {
Class<?> klass = object.getClass();
for (Class<?> iface : klass.getInterfaces()) {
@@ -152,13 +163,7 @@ class ForkServer implements Runnable, Ch
*/
private Object readObject(ClassLoader loader)
throws IOException, ClassNotFoundException {
- int n = input.readInt();
- byte[] data = new byte[n];
- input.readFully(data);
-
- ObjectInputStream deserializer =
- new ForkObjectInputStream(new ByteArrayInputStream(data), loader);
- Object object = deserializer.readObject();
+ Object object = ForkObjectInputStream.readObject(input, loader);
if (object instanceof ForkProxy) {
((ForkProxy) object).init(input, output);
}