public void parse(InputStream stream, ContentHandler handler, Metadata metadata,
                      ParseContext context) throws IOException, SAXException, TikaException {
        if (stream == null) {
            throw new NullPointerException("null stream");
        }

        Throwable t;

        boolean alive = false;
        ForkClient client = acquireClient();
        try {
            ContentHandler tee =
                    (handler instanceof AbstractRecursiveParserWrapperHandler) ? handler :
                            new TeeContentHandler(handler, new MetadataContentHandler(metadata));

            t = client.call("parse", stream, tee, metadata, context);
            alive = true;
        } catch (TikaException te) {
            // Problem occurred on our side
            alive = true;
            throw te;
        } catch (IOException e) {
            // Problem occurred on the other side
            throw new TikaException("Failed to communicate with a forked parser process." +
                    " The process has most likely crashed due to some error" +
                    " like running out of memory. A new process will be" +
                    " started for the next parsing request.", e);
        } finally {
            releaseClient(client, alive);
        }

        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);
        }
    }
@Test
    public void testRPWWithNonSerializableContentHandler() throws Exception {
        Parser parser = new AutoDetectParser();
        RecursiveParserWrapper wrapper = new RecursiveParserWrapper(parser);
        RecursiveParserWrapperHandler handler =
                new RecursiveParserWrapperHandler(new NonSerializableHandlerFactory());
        try (ForkParser fork = new ForkParser(ForkParserTest.class.getClassLoader(), wrapper);
                InputStream is = getResourceAsStream("/test-documents/embedded_then_npe.xml")) {
            Metadata metadata = new Metadata();
            ParseContext context = new ParseContext();
            fork.parse(is, handler, metadata, context);
            fail();
        } catch (TikaException e) {
            assertTrue(e.getCause() instanceof NullPointerException);
            assertContains("another", e.getCause().getMessage());
        }
        List<Metadata> metadataList = handler.getMetadataList();
        Metadata m0 = metadataList.get(0);
        assertEquals("Nikolai Lobachevsky", m0.get(TikaCoreProperties.CREATOR));
        assertContains("main_content", m0.get(TikaCoreProperties.TIKA_CONTENT));
        assertContains("embed1.xml", m0.get(TikaCoreProperties.TIKA_CONTENT));

        Metadata m1 = metadataList.get(1);
        assertEquals("embeddedAuthor", m1.get(TikaCoreProperties.CREATOR));
        assertContains("some_embedded_content", m1.get(TikaCoreProperties.TIKA_CONTENT));
        assertEquals("/embed1.xml", m1.get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
    }