You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tika.apache.org by ta...@apache.org on 2021/06/09 15:37:32 UTC

[tika] branch branch_1x updated (10c94ff -> e8ec223)

This is an automated email from the ASF dual-hosted git repository.

tallison pushed a change to branch branch_1x
in repository https://gitbox.apache.org/repos/asf/tika.git.


    from 10c94ff  fix for change in mp4parser behavior
     new 499e1c9  TIKA-3407 -- fix jaxb version and clean up related issues
     new fd98eee  TIKA-3441 -- prevent infinite loop on failure to bind to a port
     new d7fa2cd  TIKA-3441 -- improve likelihood that tesseract processes will be shutdown on crash.
     new e8ec223  Merge remote-tracking branch 'origin/branch_1x' into branch_1x

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 tika-langdetect/pom.xml                            | 10 ---
 tika-parent/pom.xml                                | 10 ++-
 tika-parsers/pom.xml                               | 28 -------
 .../apache/tika/parser/ocr/TesseractOCRParser.java | 91 ++++++++++++----------
 tika-server/pom.xml                                | 64 ---------------
 .../java/org/apache/tika/server/TikaServerCli.java | 60 ++++++++++----
 .../org/apache/tika/server/TikaServerWatchDog.java | 55 ++++++++++---
 tika-translate/pom.xml                             | 47 +----------
 8 files changed, 149 insertions(+), 216 deletions(-)

[tika] 03/04: TIKA-3441 -- improve likelihood that tesseract processes will be shutdown on crash.

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch branch_1x
in repository https://gitbox.apache.org/repos/asf/tika.git

commit d7fa2cd284a0d400a1ef29f7111018bb16b1cc5d
Author: tallison <ta...@apache.org>
AuthorDate: Wed Jun 9 11:37:02 2021 -0400

    TIKA-3441 -- improve likelihood that tesseract processes will be shutdown on crash.
---
 .../apache/tika/parser/ocr/TesseractOCRParser.java | 91 ++++++++++++----------
 1 file changed, 52 insertions(+), 39 deletions(-)

diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/ocr/TesseractOCRParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/ocr/TesseractOCRParser.java
index b2c4496..fa52248 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/ocr/TesseractOCRParser.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/ocr/TesseractOCRParser.java
@@ -530,37 +530,52 @@ public class TesseractOCRParser extends AbstractParser implements Initializable
         
         ProcessBuilder pb = new ProcessBuilder(cmd);
         setEnv(config, pb);
-        final Process process = pb.start();
+        Process process = null;
+        try {
+            process = pb.start();
+            runOCRProcess(process, config.getTimeout());
+        } finally {
+            if (process != null) {
+                process.destroyForcibly();
+            }
+        }
+    }
 
+    private void runOCRProcess(Process process, int timeout) throws IOException, TikaException {
         process.getOutputStream().close();
         InputStream out = process.getInputStream();
         InputStream err = process.getErrorStream();
-
-        logStream("OCR MSG", out, input);
-        logStream("OCR ERROR", err, input);
-
-        FutureTask<Integer> waitTask = new FutureTask<>(new Callable<Integer>() {
-            public Integer call() throws Exception {
-                return process.waitFor();
-            }
-        });
-
-        Thread waitThread = new Thread(waitTask);
-        waitThread.start();
-
+        StringBuilder outBuilder = new StringBuilder();
+        StringBuilder errBuilder = new StringBuilder();
+        Thread outThread = logStream(out, outBuilder);
+        Thread errThread = logStream(err, errBuilder);
+        outThread.start();
+        errThread.start();
+
+        int exitValue = Integer.MIN_VALUE;
         try {
-            waitTask.get(config.getTimeout(), TimeUnit.SECONDS);
+            boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
+            if (!finished) {
+                throw new TikaException("TesseractOCRParser timeout");
+            }
+            exitValue = process.exitValue();
         } catch (InterruptedException e) {
-            waitThread.interrupt();
-            process.destroy();
             Thread.currentThread().interrupt();
             throw new TikaException("TesseractOCRParser interrupted", e);
-        } catch (ExecutionException e) {
-            // should not be thrown
-        } catch (TimeoutException e) {
-            waitThread.interrupt();
-            process.destroy();
-            throw new TikaException("TesseractOCRParser timeout", e);
+        } catch (IllegalThreadStateException e) {
+            //this _should_ never be thrown
+            throw new TikaException("TesseractOCRParser timeout");
+        }
+        if (exitValue > 0) {
+            try {
+                //make sure this thread is actually done
+                errThread.join(1000);
+            } catch (InterruptedException e) {
+                //swallow
+            }
+            throw new TikaException(
+                    "TesseractOCRParser bad exit value " + exitValue + " err msg: " +
+                            errBuilder.toString());
         }
     }
 
@@ -607,24 +622,22 @@ public class TesseractOCRParser extends AbstractParser implements Initializable
      * stream of the given process to not block the process. The stream is closed
      * once fully processed.
      */
-    private void logStream(final String logType, final InputStream stream, final File file) {
-        new Thread() {
-            public void run() {
-                Reader reader = new InputStreamReader(stream, UTF_8);
-                StringBuilder out = new StringBuilder();
-                char[] buffer = new char[1024];
-                try {
-                    for (int n = reader.read(buffer); n != -1; n = reader.read(buffer))
-                        out.append(buffer, 0, n);
-                } catch (IOException e) {
-
-                } finally {
-                    IOUtils.closeQuietly(stream);
+    private Thread logStream(final InputStream stream, final StringBuilder out) {
+        return new Thread(() -> {
+            Reader reader = new InputStreamReader(stream, UTF_8);
+            char[] buffer = new char[1024];
+            try {
+                for (int n = reader.read(buffer); n != -1; n = reader.read(buffer)) {
+                    out.append(buffer, 0, n);
                 }
-
-                LOG.debug("{}", out);
+            } catch (IOException e) {
+                //swallow
+            } finally {
+                IOUtils.closeQuietly(stream);
             }
-        }.start();
+
+            LOG.debug("{}", out);
+        });
     }
 
     static String getTesseractProg() {

[tika] 01/04: TIKA-3407 -- fix jaxb version and clean up related issues

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch branch_1x
in repository https://gitbox.apache.org/repos/asf/tika.git

commit 499e1c9bdbe3ba82cc1078405ce3ebc1787a52b8
Author: tallison <ta...@apache.org>
AuthorDate: Tue Jun 1 16:34:23 2021 -0400

    TIKA-3407 -- fix jaxb version and clean up related issues
---
 tika-langdetect/pom.xml | 10 --------
 tika-parent/pom.xml     | 10 ++++----
 tika-parsers/pom.xml    | 28 ----------------------
 tika-server/pom.xml     | 64 -------------------------------------------------
 tika-translate/pom.xml  | 47 ++----------------------------------
 5 files changed, 8 insertions(+), 151 deletions(-)

diff --git a/tika-langdetect/pom.xml b/tika-langdetect/pom.xml
index 9d5867d..86a8413 100644
--- a/tika-langdetect/pom.xml
+++ b/tika-langdetect/pom.xml
@@ -82,16 +82,6 @@
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-client</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.glassfish.jaxb</groupId>
-          <artifactId>jaxb-runtime</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>com.google.code.gson</groupId>
diff --git a/tika-parent/pom.xml b/tika-parent/pom.xml
index 7d3cb93..a767a26 100644
--- a/tika-parent/pom.xml
+++ b/tika-parent/pom.xml
@@ -344,11 +344,13 @@
 
     <cxf.version>3.4.3</cxf.version>
     <slf4j.version>1.7.30</slf4j.version>
-        <log4j.version>1.2.17</log4j.version>
-    <jackson.version>2.12.2</jackson.version>
+    <log4j.version>1.2.17</log4j.version>
+    <jackson.version>2.12.3</jackson.version>
     <!-- when this is next upgraded, see if we can get rid of
-         javax.activation dependency in tika-server -->
-    <jaxb.version>3.0.0</jaxb.version>
+         javax.activation dependency in tika-server.
+         Until then, DO NOT go above 2.x unless you know what you're doing.
+         See TIKA-3407 -->
+    <jaxb.version>2.3.3</jaxb.version>
     <cli.version>1.4</cli.version>
     <lucene.version>8.8.1</lucene.version>
     <mockito.version>3.8.0</mockito.version>
diff --git a/tika-parsers/pom.xml b/tika-parsers/pom.xml
index 684c26b..2df24d5 100644
--- a/tika-parsers/pom.xml
+++ b/tika-parsers/pom.xml
@@ -395,28 +395,6 @@
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-client</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>javax.annotation</groupId>
-          <artifactId>javax.annotation-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.glassfish.jaxb</groupId>
-          <artifactId>jaxb-runtime</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>jakarta.xml.bind</groupId>
-          <artifactId>jakarta.xml.bind-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.fasterxml.woodstox</groupId>
-          <artifactId>woodstox-core</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.glassfish.jaxb</groupId>
@@ -921,12 +899,6 @@
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
       <version>${jackson.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-annotations</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
diff --git a/tika-server/pom.xml b/tika-server/pom.xml
index 2bd7d65..ad4bcb4 100644
--- a/tika-server/pom.xml
+++ b/tika-server/pom.xml
@@ -76,62 +76,22 @@
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-frontend-jaxrs</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>javax.annotation</groupId>
-          <artifactId>javax.annotation-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <artifactId>jaxb-runtime</artifactId>
-          <groupId>org.glassfish.jaxb</groupId>
-        </exclusion>
-        <exclusion>
-          <groupId>jakarta.xml.bind</groupId>
-          <artifactId>jakarta.xml.bind-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.fasterxml.woodstox</groupId>
-          <artifactId>woodstox-core</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-service-description</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-transports-http-jetty</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-security-cors</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>commons-cli</groupId>
@@ -152,12 +112,6 @@
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-client</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
 
     <!-- logging -->
@@ -184,24 +138,6 @@
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-features-metrics</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>io.dropwizard.metrics</groupId>
-          <artifactId>metrics-core</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>io.dropwizard.metrics</groupId>
-          <artifactId>metrics-jmx</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>io.micrometer</groupId>
-          <artifactId>micrometer-core</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>io.github.mweirauch</groupId>
diff --git a/tika-translate/pom.xml b/tika-translate/pom.xml
index 91d724f..47566ac 100644
--- a/tika-translate/pom.xml
+++ b/tika-translate/pom.xml
@@ -66,60 +66,23 @@
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-frontend-jaxrs</artifactId>
       <version>${cxf.version}</version>
-      <exclusions>
-        <!-- exclude because, as of 2.9.5, jaxb-annotations
-        is bringing in 2.9.0 of core's annotations
-        -->
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-annotations</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.glassfish.jaxb</groupId>
-          <artifactId>jaxb-runtime</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>jakarta.xml.bind</groupId>
-          <artifactId>jakarta.xml.bind-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.sun.activation</groupId>
-          <artifactId>jakarta.activation</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.jaxrs</groupId>
       <artifactId>jackson-jaxrs-json-provider</artifactId>
       <version>${jackson.version}</version>
       <exclusions>
-        <!-- exclude because, as of 2.9.5, jaxrs-json-provider
-        is bringing in 2.9.0 of core's annotations
-        -->
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-annotations</artifactId>
-        </exclusion>
         <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-databind</artifactId>
+          <groupId>jakarta.activation</groupId>
+          <artifactId>jakarta.activation-api</artifactId>
         </exclusion>
         <exclusion>
           <groupId>jakarta.xml.bind</groupId>
           <artifactId>jakarta.xml.bind-api</artifactId>
         </exclusion>
-        <exclusion>
-          <groupId>jakarta.activation</groupId>
-          <artifactId>jakarta.activation-api</artifactId>
-        </exclusion>
       </exclusions>
     </dependency>
     <dependency>
-      <groupId>jakarta.xml.bind</groupId>
-      <artifactId>jakarta.xml.bind-api</artifactId>
-      <version>3.0.0</version>
-    </dependency>
-    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
       <version>${jackson.version}</version>
@@ -128,12 +91,6 @@
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
       <version>${jackson.version}</version>
-      <exclusions>
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-annotations</artifactId>
-        </exclusion>
-      </exclusions>
     </dependency>
 
     <!-- Test dependencies -->

[tika] 04/04: Merge remote-tracking branch 'origin/branch_1x' into branch_1x

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch branch_1x
in repository https://gitbox.apache.org/repos/asf/tika.git

commit e8ec2233faa57f6dab8f2aa7f582203a3c707af6
Merge: d7fa2cd 10c94ff
Author: tallison <ta...@apache.org>
AuthorDate: Wed Jun 9 11:37:17 2021 -0400

    Merge remote-tracking branch 'origin/branch_1x' into branch_1x

 CHANGES.txt                                        |  2 ++
 .../java/org/apache/tika/parser/pdf/PDFParser.java |  1 +
 .../apache/tika/parser/pdf/PDFPreflightParser.java |  5 ++++
 .../org/apache/tika/parser/mp4/MP4ParserTest.java  | 13 +++++++---
 .../org/apache/tika/parser/pdf/PDFParserTest.java  | 13 ++++++++++
 .../parser/pdf/tika-skip-annotations-config.xml    | 28 ++++++++++++++++++++++
 6 files changed, 59 insertions(+), 3 deletions(-)

[tika] 02/04: TIKA-3441 -- prevent infinite loop on failure to bind to a port

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch branch_1x
in repository https://gitbox.apache.org/repos/asf/tika.git

commit fd98eeefc968b7e564d5446ae774f7f1f21aed93
Author: tallison <ta...@apache.org>
AuthorDate: Wed Jun 9 11:17:45 2021 -0400

    TIKA-3441 -- prevent infinite loop on failure to bind to a port
---
 .../java/org/apache/tika/server/TikaServerCli.java | 60 ++++++++++++++++------
 .../org/apache/tika/server/TikaServerWatchDog.java | 55 ++++++++++++++++----
 2 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java b/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java
index d2d8ba3..95c1e87 100644
--- a/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java
+++ b/tika-server/src/main/java/org/apache/tika/server/TikaServerCli.java
@@ -20,6 +20,7 @@ package org.apache.tika.server;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.lang.management.ManagementFactory;
+import java.net.BindException;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -46,6 +47,7 @@ import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
 import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
 import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter;
+import org.apache.cxf.service.factory.ServiceConstructionException;
 import org.apache.cxf.transport.common.gzip.GZIPInInterceptor;
 import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor;
 import org.apache.tika.Tika;
@@ -85,6 +87,8 @@ import org.slf4j.LoggerFactory;
 public class TikaServerCli {
 
 
+    public static final int BIND_EXCEPTION = 42;
+
     //used in spawn-child mode
     private static final long DEFAULT_MAX_FILES = 100000;
 
@@ -177,10 +181,28 @@ public class TikaServerCli {
                     }
                 }
             }
-            executeLegacy(line, options);
+            try {
+                executeLegacy(line, options);
+            } catch (ServiceConstructionException e) {
+                if (isBindException(e)) {
+                    LOG.warn("failed to bind to port", e);
+                    System.exit(BIND_EXCEPTION);
+                }
+                throw e;
+            }
         }
     }
 
+    private static boolean isBindException(Throwable e) {
+        if (e == null) {
+            return false;
+        }
+        if (e instanceof BindException) {
+            return true;
+        }
+        return isBindException(e.getCause());
+    }
+
     private static String[] stripChildArgs(String[] args) {
         List<String> ret = new ArrayList<>();
         for (int i = 0; i < args.length; i++) {
@@ -288,27 +310,16 @@ public class TikaServerCli {
             String serverId = line.hasOption("i") ? line.getOptionValue("i") : UUID.randomUUID().toString();
             LOG.debug("SERVER ID:" +serverId);
             ServerStatus serverStatus;
+            //this is used in a forked process to write status to the forking process
+            //and to check status from forking process
+            //it will be null if running in legacy no fork mode
             //if this is a child process
             if (line.hasOption("child")) {
                 serverStatus = new ServerStatus(serverId, Integer.parseInt(line.getOptionValue("numRestarts")),
                         false);
                 //redirect!!!
-                InputStream in = System.in;
-                System.setIn(new ByteArrayInputStream(new byte[0]));
                 System.setOut(System.err);
 
-                long maxFiles = DEFAULT_MAX_FILES;
-                if (line.hasOption("maxFiles")) {
-                    maxFiles = Long.parseLong(line.getOptionValue("maxFiles"));
-                }
-
-                ServerTimeouts serverTimeouts = configureServerTimeouts(line);
-                String childStatusFile = line.getOptionValue("childStatusFile");
-                Thread serverThread =
-                new Thread(new ServerStatusWatcher(serverStatus, in,
-                        Paths.get(childStatusFile), maxFiles, serverTimeouts));
-
-                serverThread.start();
             } else {
                 serverStatus = new ServerStatus(serverId, 0, true);
             }
@@ -380,6 +391,25 @@ public class TikaServerCli {
             if (line.hasOption("metrics")) {
                 MetricsHelper.registerPostStart(sf, server);
             }
+
+            //start the forked server thread after the server has started
+            if (line.hasOption("child")) {
+                long maxFiles = DEFAULT_MAX_FILES;
+                if (line.hasOption("maxFiles")) {
+                    maxFiles = Long.parseLong(line.getOptionValue("maxFiles"));
+                }
+
+                ServerTimeouts serverTimeouts = configureServerTimeouts(line);
+                String childStatusFile = line.getOptionValue("childStatusFile");
+                InputStream in = System.in;
+                System.setIn(new ByteArrayInputStream(new byte[0]));
+
+                Thread serverThread =
+                        new Thread(new ServerStatusWatcher(serverStatus, in,
+                                Paths.get(childStatusFile), maxFiles, serverTimeouts));
+
+                serverThread.start();
+            }
             LOG.info("Started Apache Tika server at {}", url);
     }
 
diff --git a/tika-server/src/main/java/org/apache/tika/server/TikaServerWatchDog.java b/tika-server/src/main/java/org/apache/tika/server/TikaServerWatchDog.java
index 8e711f7..03b023c 100644
--- a/tika-server/src/main/java/org/apache/tika/server/TikaServerWatchDog.java
+++ b/tika-server/src/main/java/org/apache/tika/server/TikaServerWatchDog.java
@@ -17,7 +17,6 @@
 
 package org.apache.tika.server;
 
-import org.apache.tika.io.MappedBufferCleaner;
 import org.apache.tika.utils.ProcessUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,9 +27,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintStream;
+import java.net.BindException;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.nio.channels.OverlappingFileLockException;
@@ -38,7 +37,6 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
 import java.time.Duration;
 import java.time.Instant;
 import java.util.ArrayList;
@@ -72,23 +70,23 @@ public class TikaServerWatchDog {
         startPingTimer(serverTimeouts);
         try {
             int restarts = 0;
-            childProcess = new ChildProcess(args, restarts, serverTimeouts);
+            childProcess = startChildProcess(args, restarts, serverTimeouts);
             setChildStatus(CHILD_STATUS.RUNNING);
             while (true) {
                 if (!childProcess.ping()) {
-                    LOG.debug("bad ping, initializing");
+                    LOG.info("bad ping. restarting.");
                     restarts++;
+                    if (serverTimeouts.getMaxRestarts() > -1 && restarts >= serverTimeouts.getMaxRestarts()) {
+                        LOG.warn("hit max restarts: "+restarts+". Stopping now");
+                        break;
+                    }
                     setChildStatus(CHILD_STATUS.INITIALIZING);
                     lastPing = null;
                     childProcess.close();
-                    LOG.debug("About to restart the child process");
-                    childProcess = new ChildProcess(args, restarts, serverTimeouts);
+                    LOG.info("About to restart the child process");
+                    childProcess = startChildProcess(args, restarts, serverTimeouts);
                     LOG.info("Successfully restarted child process -- {} restarts so far)", restarts);
                     setChildStatus(CHILD_STATUS.RUNNING);
-                    if (serverTimeouts.getMaxRestarts() > -1 && restarts >= serverTimeouts.getMaxRestarts()) {
-                        LOG.warn("hit max restarts: "+restarts+". Stopping now");
-                        break;
-                    }
                 }
                 Thread.sleep(serverTimeouts.getPingPulseMillis());
             }
@@ -104,6 +102,28 @@ public class TikaServerWatchDog {
         }
     }
 
+    private ChildProcess startChildProcess(String[] args, int restarts,
+                                           ServerTimeouts serverTimeouts) throws Exception {
+        int consecutiveRestarts = 0;
+        //if there's a bind exception, retry for 5 seconds to give the OS
+        //a chance to release the port
+        int maxBind = 5;
+        while (consecutiveRestarts < maxBind) {
+            try {
+                return new ChildProcess(args, restarts, serverTimeouts);
+            } catch (BindException e) {
+                LOG.warn("WatchDog observes bind exception on retry {}. " +
+                        "Will retry {} times.", consecutiveRestarts, maxBind);
+                consecutiveRestarts++;
+                Thread.sleep(1000);
+                if (consecutiveRestarts > maxBind) {
+                    throw e;
+                }
+            }
+        }
+        throw new RuntimeException("Couldn't start child process");
+    }
+
     private String[] addIdIfMissing(String[] args) {
         for (String arg : args) {
             //id is already specified, leave the array as is
@@ -272,6 +292,9 @@ public class TikaServerWatchDog {
             }
             if (!process.isAlive()) {
                 close();
+                if (process.exitValue() == TikaServerCli.BIND_EXCEPTION) {
+                    throw new BindException("couldn't bind");
+                }
                 throw new RuntimeException("Failed to start child process -- child is not alive");
             }
             if (!Files.exists(childStatusFile)) {
@@ -448,6 +471,7 @@ public class TikaServerWatchDog {
 
     private static synchronized void destroyChildForcibly(Process process) {
         process = process.destroyForcibly();
+
         try {
             boolean destroyed = process.waitFor(60, TimeUnit.SECONDS);
             if (! destroyed) {
@@ -455,7 +479,16 @@ public class TikaServerWatchDog {
                         "Shutting down the parent.");
                 System.exit(1);
             }
+            try {
+                int exitValue = process.exitValue();
+                LOG.info("Forked (child) process shut down with exit value: {}", exitValue);
+            } catch (IllegalThreadStateException e) {
+                LOG.error("Child process still alive when trying to read exit value. " +
+                        "Shutting down the parent.");
+                System.exit(1);
+            }
         } catch (InterruptedException e) {
+            LOG.warn("interrupted exception while trying to destroy the forked process");
             //swallow
         }
     }