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/02/03 17:49:55 UTC
[tika] branch main updated: TIKA-3288 (#401)
This is an automated email from the ASF dual-hosted git repository.
tallison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new c7e184f TIKA-3288 (#401)
c7e184f is described below
commit c7e184f83fceacd9059124bcb69fb356dd0190f7
Author: Tim Allison <ta...@apache.org>
AuthorDate: Wed Feb 3 12:49:44 2021 -0500
TIKA-3288 (#401)
TIKA-3288 -- add an async handler
---
.../src/main/java/org/apache/tika/cli/TikaCLI.java | 8 +-
.../test/java/org/apache/tika/cli/TikaCLITest.java | 18 +--
.../apache/tika/batch/fs/HandlerBuilderTest.java | 2 +-
.../apache/tika/pipes/emitter/AbstractEmitter.java | 33 ++++
.../org/apache/tika/pipes/emitter/EmitData.java | 32 ++++
.../org/apache/tika/pipes/emitter/EmitKey.java | 21 ++-
.../org/apache/tika/pipes/emitter/Emitter.java | 10 +-
.../apache/tika/pipes/emitter/EmptyEmitter.java | 7 +-
.../tika/pipes/fetchiterator/FetchEmitTuple.java | 38 +++++
.../tika/pipes/fetchiterator/FetchIterator.java | 22 +++
.../org/apache/tika/eval/app/io/ExtractReader.java | 2 -
.../resources/test-dirs/extractsA/file1.pdf.json | 2 +-
tika-eval/tika-eval-core/pom.xml | 5 +
.../tika/pipes/emitter/fs/FileSystemEmitter.java | 10 +-
.../apache/tika/pipes/emitter/s3/S3Emitter.java | 4 +-
tika-pipes/tika-emitters/tika-emitter-solr/pom.xml | 5 +
.../tika/pipes/emitter/solr/SolrEmitter.java | 128 ++++++++++-----
.../apache/tika/pipes/emitter/solr/TestBasic.java | 48 ++++--
.../pipes/fetchiterator/csv/CSVFetchIterator.java | 3 +-
.../fetchiterator/jdbc/JDBCFetchIterator.java | 2 +-
.../pipes/fetchiterator/s3/S3FetchIterator.java | 2 +-
tika-pipes/tika-httpclient-commons/pom.xml | 5 -
.../org/apache/tika/client/HttpClientUtil.java | 28 ++++
.../apache/tika/pipes/PipeIntegrationTests.java | 2 +-
tika-serialization/pom.xml | 7 +-
.../tika/metadata/serialization/JsonEmitData.java | 45 ++++++
.../metadata/serialization/JsonFetchEmitTuple.java | 150 ++++++++++++++++++
.../serialization/JsonFetchEmitTupleList.java | 68 ++++++++
.../tika/metadata/serialization/JsonMetadata.java | 128 ++++++++++-----
.../metadata/serialization/JsonMetadataBase.java | 52 ------
.../serialization/JsonMetadataDeserializer.java | 73 ---------
.../metadata/serialization/JsonMetadataList.java | 80 +++++-----
.../serialization/JsonMetadataSerializer.java | 97 ------------
.../serialization/JsonStreamingSerializer.java | 34 ++--
.../serialization/PrettyMetadataKeyComparator.java | 11 +-
.../serialization/JsonFetchEmitTupleListTest.java | 62 ++++++++
.../serialization/JsonFetchEmitTupleTest.java | 53 +++++++
.../serialization/JsonMetadataListTest.java | 20 ++-
.../metadata/serialization/JsonMetadataTest.java | 23 ++-
.../tika/server/classic/TikaDetectorsTest.java | 10 +-
.../tika/server/classic/TikaMimeTypesTest.java | 8 +-
.../tika/server/classic/TikaParsersTest.java | 9 +-
tika-server/tika-server-client/pom.xml | 10 +-
.../org/apache/tika/server/client/TikaClient.java | 55 ++-----
.../apache/tika/server/client/TikaClientCLI.java | 39 ++++-
.../apache/tika/server/client/TikaHttpClient.java | 38 +++--
.../org/apache/tika/server/core/ServerStatus.java | 2 +-
.../tika/server/core/ServerStatusWatcher.java | 2 +-
.../org/apache/tika/server/core/TikaServerCli.java | 3 +
.../apache/tika/server/core/TikaServerProcess.java | 82 ++++++++--
.../tika/server/core/resource/AsyncEmitter.java | 141 +++++++++++++++++
.../tika/server/core/resource/AsyncParser.java | 142 +++++++++++++++++
.../tika/server/core/resource/AsyncRequest.java | 19 ++-
.../tika/server/core/resource/AsyncResource.java | 167 ++++++++++++++++++++
.../tika/server/core/resource/EmitterResource.java | 113 +++++++++----
.../server/core/resource/MetadataResource.java | 2 +-
.../core/resource/RecursiveMetadataResource.java | 40 +++--
.../tika/server/core/resource/TikaDetectors.java | 10 +-
.../tika/server/core/resource/TikaMimeTypes.java | 11 +-
.../tika/server/core/resource/TikaParsers.java | 17 +-
.../tika/server/core/resource/TikaResource.java | 13 +-
.../server/core/resource/UnpackerResource.java | 2 +-
.../server/core/writer/JSONMessageBodyWriter.java | 10 +-
.../tika/server/core/writer/JSONObjWriter.java | 9 +-
.../core/writer/MetadataListMessageBodyWriter.java | 10 +-
.../apache/tika/server/core/TikaEmitterTest.java | 79 +++++-----
.../apache/tika/server/core/TikaMimeTypesTest.java | 3 -
...st.java => TikaServerAsyncIntegrationTest.java} | 170 ++++++++------------
.../core/TikaServerEmitterIntegrationTest.java | 175 +++++++++++++++------
.../server/core/TikaServerIntegrationTest.java | 84 +++++-----
.../tika/server/core/TikaServerStatusTest.java | 16 +-
71 files changed, 1931 insertions(+), 900 deletions(-)
diff --git a/tika-app/src/main/java/org/apache/tika/cli/TikaCLI.java b/tika-app/src/main/java/org/apache/tika/cli/TikaCLI.java
index 2849f1a..47ba493 100644
--- a/tika-app/src/main/java/org/apache/tika/cli/TikaCLI.java
+++ b/tika-app/src/main/java/org/apache/tika/cli/TikaCLI.java
@@ -531,11 +531,7 @@ public class TikaCLI {
}
JsonMetadataList.setPrettyPrinting(prettyPrint);
Writer writer = getOutputWriter(output, encoding);
- try {
- JsonMetadataList.toJson(handler.getMetadataList(), writer);
- } finally {
- writer.flush();
- }
+ JsonMetadataList.toJson(handler.getMetadataList(), writer);
}
private ContentHandlerFactory getContentHandlerFactory(OutputType type) {
@@ -1233,7 +1229,7 @@ public class TikaCLI {
JsonMetadata.setPrettyPrinting(prettyPrint);
JsonMetadata.toJson(metadata, writer);
writer.flush();
- } catch (TikaException e) {
+ } catch (IOException e) {
throw new SAXException(e);
}
}
diff --git a/tika-app/src/test/java/org/apache/tika/cli/TikaCLITest.java b/tika-app/src/test/java/org/apache/tika/cli/TikaCLITest.java
index c7d4f52..df0bbc8 100644
--- a/tika-app/src/test/java/org/apache/tika/cli/TikaCLITest.java
+++ b/tika-app/src/test/java/org/apache/tika/cli/TikaCLITest.java
@@ -220,10 +220,8 @@ public class TikaCLITest {
public void testJsonMetadataPrettyPrintOutput() throws Exception {
String json = getParamOutContent("--json", "-r", resourcePrefix + "testJsonMultipleInts.html");
- assertTrue(json.contains(" \"X-TIKA:Parsed-By\": [\n" +
- " \"org.apache.tika.parser.DefaultParser\",\n" +
- " \"org.apache.tika.parser.html.HtmlParser\"\n" +
- " ],\n"));
+ assertTrue(json.contains("\"X-TIKA:Parsed-By\" : [ \"org.apache.tika.parser.DefaultParser\", " +
+ "\"org.apache.tika.parser.html.HtmlParser\" ],"));
//test legacy alphabetic sort of keys
int enc = json.indexOf("\"Content-Encoding\"");
int fb = json.indexOf("fb:admins");
@@ -478,17 +476,17 @@ public class TikaCLITest {
public void testJsonRecursiveMetadataParserMetadataOnly() throws Exception {
String content = getParamOutContent("-m", "-J", "-r", resourcePrefix+"test_recursive_embedded.docx");
assertTrue(content.contains(
- "\"extended-properties:AppVersion\": \"15.0000\","));
+ "\"extended-properties:AppVersion\" : \"15.0000\","));
assertTrue(content.contains(
- "\"extended-properties:Application\": \"Microsoft Office Word\","));
- assertTrue(content.contains("\"X-TIKA:embedded_resource_path\": \"/embed1.zip\""));
+ "\"extended-properties:Application\" : \"Microsoft Office Word\","));
+ assertTrue(content.contains("\"X-TIKA:embedded_resource_path\" : \"/embed1.zip\""));
assertFalse(content.contains("X-TIKA:content"));
}
@Test
public void testJsonRecursiveMetadataParserDefault() throws Exception {
String content = getParamOutContent("-J", "-r", resourcePrefix+"test_recursive_embedded.docx");
- assertTrue(content.contains("\"X-TIKA:content\": \"\\u003chtml xmlns\\u003d\\\"http://www.w3.org/1999/xhtml"));
+ assertTrue(content.contains("\"X-TIKA:content\" : \"<html xmlns=\\\"http://www.w3.org/1999/xhtml"));
}
@Test
@@ -502,8 +500,8 @@ public class TikaCLITest {
public void testDigestInJson() throws Exception {
String content = getParamOutContent("-J", "-r", "-t", "--digest=MD5",
resourcePrefix+"test_recursive_embedded.docx");
- assertTrue(content.contains("\"X-TIKA:digest:MD5\": \"59f626e09a8c16ab6dbc2800c685f772\","));
- assertTrue(content.contains("\"X-TIKA:digest:MD5\": \"f9627095ef86c482e61d99f0cc1cf87d\""));
+ assertTrue(content.contains("\"X-TIKA:digest:MD5\" : \"59f626e09a8c16ab6dbc2800c685f772\","));
+ assertTrue(content.contains("\"X-TIKA:digest:MD5\" : \"f9627095ef86c482e61d99f0cc1cf87d\""));
}
@Test
diff --git a/tika-batch/src/test/java/org/apache/tika/batch/fs/HandlerBuilderTest.java b/tika-batch/src/test/java/org/apache/tika/batch/fs/HandlerBuilderTest.java
index 6e3648a..82a1f2b 100644
--- a/tika-batch/src/test/java/org/apache/tika/batch/fs/HandlerBuilderTest.java
+++ b/tika-batch/src/test/java/org/apache/tika/batch/fs/HandlerBuilderTest.java
@@ -109,7 +109,7 @@ public class HandlerBuilderTest extends FSBatchTestBase {
Path outputFile = outputDir.resolve("test0.xml.json");
String resultString = readFileToString(outputFile, UTF_8);
assertTrue(resultString.contains("\"author\":\"Nikolai Lobachevsky\""));
- assertTrue(resultString.contains("tika-batch\\u0027s first test file"));
+ assertTrue(resultString.contains("tika-batch's first test file"));
}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java b/tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java
index 1117537..a54b708 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java
+++ b/tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java
@@ -17,6 +17,10 @@
package org.apache.tika.pipes.emitter;
import org.apache.tika.config.Field;
+import org.apache.tika.metadata.Metadata;
+
+import java.io.IOException;
+import java.util.List;
public abstract class AbstractEmitter implements Emitter {
@@ -31,4 +35,33 @@ public abstract class AbstractEmitter implements Emitter {
public String getName() {
return name;
}
+
+ /**
+ * The default behavior is to call {@link #emit(String, List)} on each item.
+ * Some implementations, e.g. Solr/ES/vespa, can benefit from subclassing this and
+ * emitting a bunch of docs at once.
+ *
+ * @param emitData
+ * @throws IOException
+ * @throws TikaEmitterException
+ */
+ @Override
+ public void emit(List<EmitData> emitData) throws IOException, TikaEmitterException {
+ for (EmitData d : emitData) {
+ emit(d.getEmitKey().getKey(), d.getMetadataList());
+ }
+ }
+
+ public static long estimateSizeInBytes(String id, List<Metadata> metadataList) {
+ long sz = 36 + id.length() * 2;
+ for (Metadata m : metadataList) {
+ for (String n : m.names()) {
+ sz += 36 + n.length() * 2;
+ for (String v : m.getValues(n)) {
+ sz += 36 + v.length() * 2;
+ }
+ }
+ }
+ return sz;
+ }
}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitData.java b/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitData.java
new file mode 100644
index 0000000..0063c6a
--- /dev/null
+++ b/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitData.java
@@ -0,0 +1,32 @@
+package org.apache.tika.pipes.emitter;
+
+import org.apache.tika.metadata.Metadata;
+
+import java.util.List;
+
+public class EmitData {
+
+ private final EmitKey emitKey;
+ private final List<Metadata> metadataList;
+
+ public EmitData(EmitKey emitKey, List<Metadata> metadataList) {
+ this.emitKey = emitKey;
+ this.metadataList = metadataList;
+ }
+
+ public EmitKey getEmitKey() {
+ return emitKey;
+ }
+
+ public List<Metadata> getMetadataList() {
+ return metadataList;
+ }
+
+ @Override
+ public String toString() {
+ return "EmitData{" +
+ "emitKey=" + emitKey +
+ ", metadataList=" + metadataList +
+ '}';
+ }
+}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitKey.java b/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitKey.java
index 47a8ee7..eb4c2c2 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitKey.java
+++ b/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmitKey.java
@@ -30,7 +30,7 @@ public class EmitKey {
return emitterName;
}
- public String getEmitKey() {
+ public String getKey() {
return emitKey;
}
@@ -41,4 +41,23 @@ public class EmitKey {
", emitterKey='" + emitKey + '\'' +
'}';
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ EmitKey emitKey1 = (EmitKey) o;
+
+ if (emitterName != null ? !emitterName.equals(emitKey1.emitterName) : emitKey1.emitterName != null)
+ return false;
+ return emitKey != null ? emitKey.equals(emitKey1.emitKey) : emitKey1.emitKey == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = emitterName != null ? emitterName.hashCode() : 0;
+ result = 31 * result + (emitKey != null ? emitKey.hashCode() : 0);
+ return result;
+ }
}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/emitter/Emitter.java b/tika-core/src/main/java/org/apache/tika/pipes/emitter/Emitter.java
index 4f6bdae..dbea669 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/emitter/Emitter.java
+++ b/tika-core/src/main/java/org/apache/tika/pipes/emitter/Emitter.java
@@ -27,14 +27,8 @@ public interface Emitter {
void emit(String emitKey, List<Metadata> metadataList) throws IOException, TikaEmitterException;
+ void emit(List<EmitData> emitData) throws IOException, TikaEmitterException;
+ //TODO -- add this later for xhtml?
//void emit(String txt, Metadata metadata) throws IOException, TikaException;
- /*
- TODO we can add this later?
- void addBatch(String emitKey, List<Metadata> metadataList) throws IOException, TikaEmitterException;
-
- void executeBatch() throws IOException, TikaEmitterException;
-
- */
-
}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmptyEmitter.java b/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmptyEmitter.java
index 8c0ebda..5f83db7 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmptyEmitter.java
+++ b/tika-core/src/main/java/org/apache/tika/pipes/emitter/EmptyEmitter.java
@@ -16,13 +16,13 @@
*/
package org.apache.tika.pipes.emitter;
-import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import java.io.IOException;
import java.util.List;
public class EmptyEmitter implements Emitter {
+
@Override
public String getName() {
return "empty";
@@ -32,4 +32,9 @@ public class EmptyEmitter implements Emitter {
public void emit(String emitKey, List<Metadata> metadataList) throws IOException, TikaEmitterException {
}
+
+ @Override
+ public void emit(List<EmitData> emitData) throws IOException, TikaEmitterException {
+
+ }
}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchEmitTuple.java b/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchEmitTuple.java
index 9023378..efab236 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchEmitTuple.java
+++ b/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchEmitTuple.java
@@ -22,14 +22,25 @@ import org.apache.tika.pipes.fetcher.FetchKey;
public class FetchEmitTuple {
+ public enum ON_PARSE_EXCEPTION {
+ SKIP,
+ EMIT
+ }
+ public static final ON_PARSE_EXCEPTION DEFAULT_ON_PARSE_EXCEPTION = ON_PARSE_EXCEPTION.EMIT;
private final FetchKey fetchKey;
private final EmitKey emitKey;
private final Metadata metadata;
+ private final ON_PARSE_EXCEPTION onParseException;
public FetchEmitTuple(FetchKey fetchKey, EmitKey emitKey, Metadata metadata) {
+ this(fetchKey, emitKey, metadata, DEFAULT_ON_PARSE_EXCEPTION);
+ }
+ public FetchEmitTuple(FetchKey fetchKey, EmitKey emitKey, Metadata metadata,
+ ON_PARSE_EXCEPTION onParseException) {
this.fetchKey = fetchKey;
this.emitKey = emitKey;
this.metadata = metadata;
+ this.onParseException = onParseException;
}
public FetchKey getFetchKey() {
@@ -44,12 +55,39 @@ public class FetchEmitTuple {
return metadata;
}
+ public ON_PARSE_EXCEPTION getOnParseException() {
+ return onParseException;
+ }
+
@Override
public String toString() {
return "FetchEmitTuple{" +
"fetchKey=" + fetchKey +
", emitKey=" + emitKey +
", metadata=" + metadata +
+ ", onParseException=" + onParseException +
'}';
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FetchEmitTuple that = (FetchEmitTuple) o;
+
+ if (fetchKey != null ? !fetchKey.equals(that.fetchKey) : that.fetchKey != null) return false;
+ if (emitKey != null ? !emitKey.equals(that.emitKey) : that.emitKey != null) return false;
+ if (metadata != null ? !metadata.equals(that.metadata) : that.metadata != null) return false;
+ return onParseException == that.onParseException;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = fetchKey != null ? fetchKey.hashCode() : 0;
+ result = 31 * result + (emitKey != null ? emitKey.hashCode() : 0);
+ result = 31 * result + (metadata != null ? metadata.hashCode() : 0);
+ result = 31 * result + (onParseException != null ? onParseException.hashCode() : 0);
+ return result;
+ }
}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchIterator.java b/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchIterator.java
index 6b9457e..505d042 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchIterator.java
+++ b/tika-core/src/main/java/org/apache/tika/pipes/fetchiterator/FetchIterator.java
@@ -49,6 +49,8 @@ public abstract class FetchIterator implements Callable<Integer>, Initializable
private String fetcherName;
private String emitterName;
private int added = 0;
+ private FetchEmitTuple.ON_PARSE_EXCEPTION onParseException = FetchEmitTuple.ON_PARSE_EXCEPTION.EMIT;
+
public FetchIterator() {
}
@@ -95,6 +97,26 @@ public abstract class FetchIterator implements Callable<Integer>, Initializable
this.queueSize = queueSize;
}
+ @Field
+ public void setOnParseException(String onParseException) throws TikaConfigException {
+ if ("skip".equalsIgnoreCase(onParseException)) {
+ setOnParseException(FetchEmitTuple.ON_PARSE_EXCEPTION.SKIP);
+ } else if ("emit".equalsIgnoreCase(onParseException)) {
+ setOnParseException(FetchEmitTuple.ON_PARSE_EXCEPTION.EMIT);
+ } else {
+ throw new TikaConfigException("must be either 'skip' or 'emit': "
+ + onParseException);
+ }
+ }
+
+ public void setOnParseException(FetchEmitTuple.ON_PARSE_EXCEPTION onParseException) {
+ this.onParseException = onParseException;
+ }
+
+ public FetchEmitTuple.ON_PARSE_EXCEPTION getOnParseException() {
+ return onParseException;
+ }
+
@Override
public Integer call() throws Exception {
if (queue == null || numConsumers < 0) {
diff --git a/tika-eval/tika-eval-app/src/main/java/org/apache/tika/eval/app/io/ExtractReader.java b/tika-eval/tika-eval-app/src/main/java/org/apache/tika/eval/app/io/ExtractReader.java
index 40ef751..cca4c03 100644
--- a/tika-eval/tika-eval-app/src/main/java/org/apache/tika/eval/app/io/ExtractReader.java
+++ b/tika-eval/tika-eval-app/src/main/java/org/apache/tika/eval/app/io/ExtractReader.java
@@ -166,8 +166,6 @@ public class ExtractReader {
}
} catch (IOException e) {
throw new ExtractReaderException(ExtractReaderException.TYPE.IO_EXCEPTION);
- } catch (TikaException e) {
- throw new ExtractReaderException(ExtractReaderException.TYPE.EXTRACT_PARSE_EXCEPTION);
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(is);
diff --git a/tika-eval/tika-eval-app/src/test/resources/test-dirs/extractsA/file1.pdf.json b/tika-eval/tika-eval-app/src/test/resources/test-dirs/extractsA/file1.pdf.json
index 6ef09de..8e6ae43 100644
--- a/tika-eval/tika-eval-app/src/test/resources/test-dirs/extractsA/file1.pdf.json
+++ b/tika-eval/tika-eval-app/src/test/resources/test-dirs/extractsA/file1.pdf.json
@@ -1,5 +1,5 @@
[{
"Content-Type":"text/plain",
"X-TIKA:content":"the quick brown fox fox fox jumped over the lazy lazy dog 1,200 120000",
- "xmpTPg:NPages":2
+ "xmpTPg:NPages":"2"
}]
\ No newline at end of file
diff --git a/tika-eval/tika-eval-core/pom.xml b/tika-eval/tika-eval-core/pom.xml
index 26c087e..664ef2d 100644
--- a/tika-eval/tika-eval-core/pom.xml
+++ b/tika-eval/tika-eval-core/pom.xml
@@ -44,6 +44,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>${gson.version}</version>
+ </dependency>
+ <dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
diff --git a/tika-pipes/tika-emitters/tika-emitter-fs/src/main/java/org/apache/tika/pipes/emitter/fs/FileSystemEmitter.java b/tika-pipes/tika-emitters/tika-emitter-fs/src/main/java/org/apache/tika/pipes/emitter/fs/FileSystemEmitter.java
index f58a21c..d4a0448 100644
--- a/tika-pipes/tika-emitters/tika-emitter-fs/src/main/java/org/apache/tika/pipes/emitter/fs/FileSystemEmitter.java
+++ b/tika-pipes/tika-emitters/tika-emitter-fs/src/main/java/org/apache/tika/pipes/emitter/fs/FileSystemEmitter.java
@@ -41,7 +41,7 @@ import java.util.Set;
/**
* Emitter to write to a file system.
- *
+ * <p>
* This calculates the path to write to based on the {@link #basePath}
* and the value of the {@link TikaCoreProperties#SOURCE_PATH} value.
*
@@ -95,11 +95,7 @@ public class FileSystemEmitter extends AbstractEmitter implements StreamEmitter
Files.createDirectories(output.getParent());
}
try (Writer writer = Files.newBufferedWriter(output, StandardCharsets.UTF_8)) {
- try {
- JsonMetadataList.toJson(metadataList, writer);
- } catch (TikaException e) {
- throw new TikaEmitterException("can't create json", e);
- }
+ JsonMetadataList.toJson(metadataList, writer);
}
}
@@ -111,6 +107,7 @@ public class FileSystemEmitter extends AbstractEmitter implements StreamEmitter
/**
* If you want to customize the output file's file extension.
* Do not include the "."
+ *
* @param fileExtension
*/
@Field
@@ -132,6 +129,7 @@ public class FileSystemEmitter extends AbstractEmitter implements StreamEmitter
"'; must be one of: 'skip', 'replace', 'exception'");
}
}
+
@Override
public void emit(String path, InputStream inputStream, Metadata userMetadata) throws IOException,
TikaEmitterException {
diff --git a/tika-pipes/tika-emitters/tika-emitter-s3/src/main/java/org/apache/tika/pipes/emitter/s3/S3Emitter.java b/tika-pipes/tika-emitters/tika-emitter-s3/src/main/java/org/apache/tika/pipes/emitter/s3/S3Emitter.java
index d72d8fb..cb97d20 100644
--- a/tika-pipes/tika-emitters/tika-emitter-s3/src/main/java/org/apache/tika/pipes/emitter/s3/S3Emitter.java
+++ b/tika-pipes/tika-emitters/tika-emitter-s3/src/main/java/org/apache/tika/pipes/emitter/s3/S3Emitter.java
@@ -111,7 +111,7 @@ public class S3Emitter extends AbstractEmitter implements Initializable, StreamE
try (Writer writer =
new BufferedWriter(new OutputStreamWriter(bos, StandardCharsets.UTF_8))) {
JsonMetadataList.toJson(metadataList, writer);
- } catch (TikaException e) {
+ } catch (IOException e) {
throw new TikaEmitterException("can't jsonify", e);
}
byte[] bytes = bos.toByteArray();
@@ -125,7 +125,7 @@ public class S3Emitter extends AbstractEmitter implements Initializable, StreamE
try (Writer writer = Files.newBufferedWriter(tmpPath,
StandardCharsets.UTF_8, StandardOpenOption.CREATE)) {
JsonMetadataList.toJson(metadataList, writer);
- } catch (TikaException e) {
+ } catch (IOException e) {
throw new TikaEmitterException("can't jsonify", e);
}
try (InputStream is = TikaInputStream.get(tmpPath)) {
diff --git a/tika-pipes/tika-emitters/tika-emitter-solr/pom.xml b/tika-pipes/tika-emitters/tika-emitter-solr/pom.xml
index 1edfff0..e36d1c8 100644
--- a/tika-pipes/tika-emitters/tika-emitter-solr/pom.xml
+++ b/tika-pipes/tika-emitters/tika-emitter-solr/pom.xml
@@ -42,6 +42,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
diff --git a/tika-pipes/tika-emitters/tika-emitter-solr/src/main/java/org/apache/tika/pipes/emitter/solr/SolrEmitter.java b/tika-pipes/tika-emitters/tika-emitter-solr/src/main/java/org/apache/tika/pipes/emitter/solr/SolrEmitter.java
index 5830b14..0e09e9c 100644
--- a/tika-pipes/tika-emitters/tika-emitter-solr/src/main/java/org/apache/tika/pipes/emitter/solr/SolrEmitter.java
+++ b/tika-pipes/tika-emitters/tika-emitter-solr/src/main/java/org/apache/tika/pipes/emitter/solr/SolrEmitter.java
@@ -16,9 +16,8 @@
*/
package org.apache.tika.pipes.emitter.solr;
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.http.client.HttpClient;
import org.apache.tika.client.HttpClientFactory;
import org.apache.tika.client.HttpClientUtil;
@@ -28,17 +27,25 @@ import org.apache.tika.config.Initializable;
import org.apache.tika.config.InitializableProblemHandler;
import org.apache.tika.config.Param;
import org.apache.tika.pipes.emitter.AbstractEmitter;
-import org.apache.tika.pipes.emitter.Emitter;
+import org.apache.tika.pipes.emitter.EmitData;
import org.apache.tika.exception.TikaConfigException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.pipes.emitter.TikaEmitterException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.zip.GZIPOutputStream;
public class SolrEmitter extends AbstractEmitter implements Initializable {
@@ -48,10 +55,11 @@ public class SolrEmitter extends AbstractEmitter implements Initializable {
PARENT_CHILD,
//anything else?
}
- private static final Gson GSON = new Gson();
private static final String ATTACHMENTS = "attachments";
private static final String UPDATE_PATH = "/update";
private static final Logger LOG = LoggerFactory.getLogger(SolrEmitter.class);
+ //one day this will be allowed or can be configured?
+ private final boolean gzipJson = false;
private AttachmentStrategy attachmentStrategy = AttachmentStrategy.PARENT_CHILD;
private String url;
@@ -61,27 +69,77 @@ public class SolrEmitter extends AbstractEmitter implements Initializable {
private HttpClientFactory httpClientFactory;
private HttpClient httpClient;
+ public SolrEmitter() throws TikaConfigException {
+ httpClientFactory = new HttpClientFactory();
+ }
@Override
public void emit(String emitKey, List<Metadata> metadataList) throws IOException,
TikaEmitterException {
+
if (metadataList == null || metadataList.size() == 0) {
LOG.warn("metadataList is null or empty");
return;
}
- String json = jsonify(emitKey, metadataList);
- LOG.debug("emitting json:"+json);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ Writer writer = gzipJson ?
+ new BufferedWriter(
+ new OutputStreamWriter(
+ new GZIPOutputStream(bos), StandardCharsets.UTF_8)) :
+ new BufferedWriter(
+ new OutputStreamWriter(bos, StandardCharsets.UTF_8));
+ try (
+ JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ jsonGenerator.writeStartArray();
+ jsonify(jsonGenerator, emitKey, metadataList);
+ jsonGenerator.writeEndArray();
+ }
+ LOG.debug("emitting json ({})",
+ new String(bos.toByteArray(), StandardCharsets.UTF_8));
try {
HttpClientUtil.postJson(httpClient,
- url+UPDATE_PATH+"?commitWithin="+getCommitWithin(), json);
+ url+UPDATE_PATH+"?commitWithin="+getCommitWithin(), bos.toByteArray(), gzipJson);
} catch (TikaClientException e) {
throw new TikaEmitterException("can't post", e);
}
}
- private String jsonify(String emitKey, List<Metadata> metadataList) {
+ @Override
+ public void emit(List<EmitData> batch) throws IOException,
+ TikaEmitterException {
+ if (batch == null || batch.size() == 0) {
+ LOG.warn("batch is null or empty");
+ return;
+ }
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ Writer writer = gzipJson ?
+ new BufferedWriter(
+ new OutputStreamWriter(
+ new GZIPOutputStream(bos), StandardCharsets.UTF_8)) :
+ new BufferedWriter(
+ new OutputStreamWriter(bos, StandardCharsets.UTF_8));
+ try (JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ jsonGenerator.writeStartArray();
+ for (EmitData d : batch) {
+ jsonify(jsonGenerator, d.getEmitKey().getKey(), d.getMetadataList());
+ }
+ jsonGenerator.writeEndArray();
+ }
+ LOG.debug("emitting json ({})",
+ new String(bos.toByteArray(), StandardCharsets.UTF_8));
+ try {
+ HttpClientUtil.postJson(httpClient,
+ url+UPDATE_PATH+"?commitWithin="+getCommitWithin(),
+ bos.toByteArray(), gzipJson);
+ } catch (TikaClientException e) {
+ throw new TikaEmitterException("can't post", e);
+ }
+ }
+
+ private void jsonify(JsonGenerator jsonGenerator, String emitKey, List<Metadata> metadataList) throws IOException {
metadataList.get(0).set(idField, emitKey);
- if (attachmentStrategy == AttachmentStrategy.SKIP) {
- return toJsonString(jsonify(metadataList.get(0)));
+ if (attachmentStrategy == AttachmentStrategy.SKIP ||
+ metadataList.size() == 1) {
+ jsonify(metadataList.get(0), jsonGenerator);
} else if (attachmentStrategy == AttachmentStrategy.CONCATENATE_CONTENT) {
//this only handles text for now, not xhtml
StringBuilder sb = new StringBuilder();
@@ -93,53 +151,47 @@ public class SolrEmitter extends AbstractEmitter implements Initializable {
}
Metadata parent = metadataList.get(0);
parent.set(getContentField(), sb.toString());
- return toJsonString(jsonify(parent));
+ jsonify(parent, jsonGenerator);
} else if (attachmentStrategy == AttachmentStrategy.PARENT_CHILD) {
- if (metadataList.size() == 1) {
- JsonObject obj = jsonify(metadataList.get(0));
- return toJsonString(obj);
- }
- JsonObject parent = jsonify(metadataList.get(0));
- JsonArray children = new JsonArray();
+ jsonify(metadataList.get(0), jsonGenerator, false);
+ jsonGenerator.writeArrayFieldStart(ATTACHMENTS);
+
for (int i = 1; i < metadataList.size(); i++) {
Metadata m = metadataList.get(i);
m.set(idField, UUID.randomUUID().toString());
- children.add(jsonify(m));
+ jsonify(m, jsonGenerator);
}
- parent.add(ATTACHMENTS, children);
- return toJsonString(parent);
+ jsonGenerator.writeEndArray();
+ jsonGenerator.writeEndObject();
} else {
throw new IllegalArgumentException("I don't yet support this attachment strategy: "
+ attachmentStrategy);
}
}
- private String toJsonString(JsonObject obj) {
- //wrap the document into an array
- //so that Solr correctly interprets this as
- //upload docs vs a command.
- JsonArray docs = new JsonArray();
- docs.add(obj);
- return GSON.toJson(docs);
- }
-
- private JsonObject jsonify(Metadata metadata) {
- JsonObject obj = new JsonObject();
+ private void jsonify(Metadata metadata, JsonGenerator jsonGenerator, boolean writeEndObject) throws IOException {
+ jsonGenerator.writeStartObject();
for (String n : metadata.names()) {
String[] vals = metadata.getValues(n);
if (vals.length == 0) {
continue;
} else if (vals.length == 1) {
- obj.addProperty(n, vals[0]);
+ jsonGenerator.writeStringField(n, vals[0]);
} else if (vals.length > 1) {
- JsonArray valArr = new JsonArray();
- for (int i = 0; i < vals.length; i++) {
- valArr.add(vals[i]);
+ jsonGenerator.writeArrayFieldStart(n);
+ for (String val : vals) {
+ jsonGenerator.writeString(val);
}
- obj.add(n, valArr);
+ jsonGenerator.writeEndArray();
}
}
- return obj;
+ if (writeEndObject) {
+ jsonGenerator.writeEndObject();
+ }
+ }
+
+ private void jsonify(Metadata metadata, JsonGenerator jsonGenerator) throws IOException {
+ jsonify(metadata, jsonGenerator, true);
}
/**
diff --git a/tika-pipes/tika-emitters/tika-emitter-solr/src/test/java/org/apache/tika/pipes/emitter/solr/TestBasic.java b/tika-pipes/tika-emitters/tika-emitter-solr/src/test/java/org/apache/tika/pipes/emitter/solr/TestBasic.java
index 14a091a..069e7a2 100644
--- a/tika-pipes/tika-emitters/tika-emitter-solr/src/test/java/org/apache/tika/pipes/emitter/solr/TestBasic.java
+++ b/tika-pipes/tika-emitters/tika-emitter-solr/src/test/java/org/apache/tika/pipes/emitter/solr/TestBasic.java
@@ -18,6 +18,9 @@ package org.apache.tika.pipes.emitter.solr;
import org.apache.tika.config.TikaConfig;
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.pipes.emitter.EmitData;
+import org.apache.tika.pipes.emitter.EmitKey;
import org.apache.tika.pipes.emitter.Emitter;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
@@ -36,23 +39,50 @@ public class TestBasic {
TikaConfig tikaConfig = new TikaConfig(
TestBasic.class.getResourceAsStream("/tika-config-simple-emitter.xml"));
Emitter emitter = tikaConfig.getEmitterManager().getEmitter("solr1");
+ List<Metadata> metadataList = getParentChild(tikaConfig,
+ "id1", 2);
+
+ emitter.emit("1", metadataList);
+ }
+
+ @Test
+ public void testBatch() throws Exception {
+ TikaConfig tikaConfig = new TikaConfig(
+ TestBasic.class.getResourceAsStream("/tika-config-simple-emitter.xml"));
+ Emitter emitter = tikaConfig.getEmitterManager().getEmitter("solr2");
+ List<EmitData> emitData = new ArrayList<>();
+ for (int i = 0; i < 100; i++) {
+ List<Metadata> metadataList = getParentChild(tikaConfig,
+ "batch_"+i, 4);
+ emitData.add(new EmitData(
+ new EmitKey(emitter.getName(), "batch_"+i),
+ metadataList));
+ }
+ emitter.emit(emitData);
+ }
+
+ private List<Metadata> getParentChild(TikaConfig tikaConfig,
+ String id, int numChildren) throws TikaException {
List<Metadata> metadataList = new ArrayList<>();
+ MetadataFilter filter = tikaConfig.getMetadataFilter();
+
Metadata m1 = new Metadata();
+ m1.set("id", id);
m1.set(Metadata.CONTENT_LENGTH, "314159");
m1.set(TikaCoreProperties.TIKA_CONTENT, "the quick brown");
m1.set(TikaCoreProperties.TITLE, "this is the first title");
m1.add(TikaCoreProperties.CREATOR, "firstAuthor");
m1.add(TikaCoreProperties.CREATOR, "secondAuthor");
-
- Metadata m2 = new Metadata();
- m2.set(TikaCoreProperties.EMBEDDED_RESOURCE_PATH, "/path_to_this.txt");
- m2.set(TikaCoreProperties.TIKA_CONTENT, "fox jumped over the lazy");
- MetadataFilter filter = tikaConfig.getMetadataFilter();
filter.filter(m1);
- filter.filter(m2);
metadataList.add(m1);
- metadataList.add(m2);
-
- emitter.emit("1", metadataList);
+ for (int i = 1; i < numChildren; i++ ) {
+ Metadata m2 = new Metadata();
+ m2.set(TikaCoreProperties.EMBEDDED_RESOURCE_PATH, "/path_to_this.txt");
+ m2.set(TikaCoreProperties.TIKA_CONTENT, "fox jumped over the lazy " + i);
+ filter.filter(m2);
+ metadataList.add(m2);
+ }
+ return metadataList;
}
+
}
diff --git a/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-csv/src/main/java/org/apache/tika/pipes/fetchiterator/csv/CSVFetchIterator.java b/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-csv/src/main/java/org/apache/tika/pipes/fetchiterator/csv/CSVFetchIterator.java
index 12268ea..7cb0c02 100644
--- a/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-csv/src/main/java/org/apache/tika/pipes/fetchiterator/csv/CSVFetchIterator.java
+++ b/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-csv/src/main/java/org/apache/tika/pipes/fetchiterator/csv/CSVFetchIterator.java
@@ -120,7 +120,8 @@ public class CSVFetchIterator extends FetchIterator implements Initializable {
Metadata metadata = loadMetadata(fetchEmitKeyIndices, headers, record);
tryToAdd(new FetchEmitTuple(
new FetchKey(fetcherName, fetchKey),
- new EmitKey(emitterName, emitKey), metadata));
+ new EmitKey(emitterName, emitKey), metadata,
+ getOnParseException()));
}
}
}
diff --git a/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-jdbc/src/main/java/org/apache/tika/pipes/fetchiterator/jdbc/JDBCFetchIterator.java b/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-jdbc/src/main/java/org/apache/tika/pipes/fetchiterator/jdbc/JDBCFetchIterator.java
index 2c5ac1a..19da544 100644
--- a/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-jdbc/src/main/java/org/apache/tika/pipes/fetchiterator/jdbc/JDBCFetchIterator.java
+++ b/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-jdbc/src/main/java/org/apache/tika/pipes/fetchiterator/jdbc/JDBCFetchIterator.java
@@ -171,7 +171,7 @@ public class JDBCFetchIterator extends FetchIterator implements Initializable {
tryToAdd(new FetchEmitTuple(
new FetchKey(fetcherName, fetchKey),
new EmitKey(emitterName, emitKey),
- metadata));
+ metadata, getOnParseException()));
}
private String toString(ResultSet rs) throws SQLException {
diff --git a/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-s3/src/main/java/org/apache/tika/pipes/fetchiterator/s3/S3FetchIterator.java b/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-s3/src/main/java/org/apache/tika/pipes/fetchiterator/s3/S3FetchIterator.java
index 2d575e9..dd14463 100644
--- a/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-s3/src/main/java/org/apache/tika/pipes/fetchiterator/s3/S3FetchIterator.java
+++ b/tika-pipes/tika-fetch-iterators/tika-fetch-iterator-s3/src/main/java/org/apache/tika/pipes/fetchiterator/s3/S3FetchIterator.java
@@ -104,7 +104,7 @@ public class S3FetchIterator extends FetchIterator implements Initializable {
tryToAdd(new FetchEmitTuple(
new FetchKey(fetcherName, summary.getKey()),
new EmitKey(fetcherName, summary.getKey()),
- new Metadata()));
+ new Metadata(), getOnParseException()));
count++;
}
long elapsed = System.currentTimeMillis() - start;
diff --git a/tika-pipes/tika-httpclient-commons/pom.xml b/tika-pipes/tika-httpclient-commons/pom.xml
index ef7797a..c33d3fb 100644
--- a/tika-pipes/tika-httpclient-commons/pom.xml
+++ b/tika-pipes/tika-httpclient-commons/pom.xml
@@ -42,11 +42,6 @@
<artifactId>httpclient</artifactId>
<version>${httpcomponents.version}</version>
</dependency>
- <dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <version>${gson.version}</version>
- </dependency>
</dependencies>
</project>
\ No newline at end of file
diff --git a/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientUtil.java b/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientUtil.java
index 780179c..11ebb3c 100644
--- a/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientUtil.java
+++ b/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientUtil.java
@@ -20,6 +20,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.InputStreamEntity;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
@@ -30,7 +31,9 @@ public class HttpClientUtil {
public static boolean postJson(HttpClient client, String url, String json) throws IOException,
TikaClientException {
HttpPost post = new HttpPost(url);
+ post.setHeader("Content-Encoding", "gzip");
ByteArrayEntity entity = new ByteArrayEntity(json.getBytes(StandardCharsets.UTF_8));
+
post.setEntity(entity);
post.setHeader("Content-Type", "application/json");
HttpResponse response = client.execute(post);
@@ -48,4 +51,29 @@ public class HttpClientUtil {
return true;
}
+ public static boolean postJson(HttpClient client, String url,
+ byte[] bytes, boolean gzipped) throws IOException,
+ TikaClientException {
+ HttpPost post = new HttpPost(url);
+ if (gzipped) {
+ post.setHeader("Content-Encoding", "gzip");
+ }
+ ByteArrayEntity entity = new ByteArrayEntity(bytes);
+
+ post.setEntity(entity);
+ post.setHeader("Content-Type", "application/json");
+ HttpResponse response = client.execute(post);
+
+
+ if (response.getStatusLine().getStatusCode() != 200) {
+ String msg = EntityUtils.toString(response.getEntity());
+ throw new TikaClientException("Bad status: " +
+ response.getStatusLine().getStatusCode() + " : "+
+ msg);
+ } else {
+ String msg = EntityUtils.toString(response.getEntity());
+ System.out.println("httputil: " + msg);
+ }
+ return true;
+ }
}
diff --git a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/PipeIntegrationTests.java b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/PipeIntegrationTests.java
index 7df2bb4..3831f07 100644
--- a/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/PipeIntegrationTests.java
+++ b/tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/PipeIntegrationTests.java
@@ -218,7 +218,7 @@ public class PipeIntegrationTests {
userMetadata.set("project", "my-project");
try (InputStream is = fetcher.fetch(t.getFetchKey().getKey(), t.getMetadata())) {
- emitter.emit(t.getEmitKey().getEmitKey(), is, userMetadata);
+ emitter.emit(t.getEmitKey().getKey(), is, userMetadata);
}
}
}
diff --git a/tika-serialization/pom.xml b/tika-serialization/pom.xml
index bc2ff93..64e3aa2 100644
--- a/tika-serialization/pom.xml
+++ b/tika-serialization/pom.xml
@@ -48,12 +48,13 @@
<groupId>${project.groupId}</groupId>
<artifactId>tika-core</artifactId>
<version>${project.version}</version>
+ <scope>provided</scope>
</dependency>
<dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <version>${gson.version}</version>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${jackson.version}</version>
</dependency>
<!-- Test dependencies -->
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonEmitData.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonEmitData.java
new file mode 100644
index 0000000..21b6377
--- /dev/null
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonEmitData.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.serialization;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.pipes.emitter.EmitData;
+import org.apache.tika.pipes.emitter.EmitKey;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public class JsonEmitData {
+
+ public static void toJson(EmitData emitData, Writer writer) throws IOException {
+ try (JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ jsonGenerator.writeStartObject();
+ EmitKey key = emitData.getEmitKey();
+ jsonGenerator.writeStringField(JsonFetchEmitTuple.EMITTER, key.getEmitterName());
+ jsonGenerator.writeStringField(JsonFetchEmitTuple.EMITKEY, key.getKey());
+ jsonGenerator.writeFieldName("data");
+ jsonGenerator.writeStartArray();
+ for (Metadata m : emitData.getMetadataList()) {
+ JsonMetadata.writeMetadataObject(m, jsonGenerator, false);
+ }
+ jsonGenerator.writeEndArray();
+ jsonGenerator.writeEndObject();
+ }
+ }
+}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonFetchEmitTuple.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonFetchEmitTuple.java
new file mode 100644
index 0000000..55d10ef
--- /dev/null
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonFetchEmitTuple.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.serialization;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.apache.tika.utils.StringUtils;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Locale;
+
+public class JsonFetchEmitTuple {
+
+ public static final String FETCHER = "fetcher";
+ public static final String FETCHKEY = "fetchKey";
+ public static final String EMITTER = "emitter";
+ public static final String EMITKEY = "emitKey";
+ public static final String METADATAKEY = "metadata";
+ public static final String ON_PARSE_EXCEPTION = "onParseException";
+
+
+ public static FetchEmitTuple fromJson(Reader reader) throws IOException {
+ JsonParser jParser = new JsonFactory().createParser(reader);
+ JsonToken token = jParser.nextToken();
+ if (token != JsonToken.START_OBJECT) {
+ throw new IOException("require start object, but see: " + token.name());
+ }
+ return parseFetchEmitTuple(jParser);
+ }
+
+
+ static FetchEmitTuple parseFetchEmitTuple(JsonParser jParser) throws IOException {
+ JsonToken token = jParser.nextToken();
+ if (token == JsonToken.START_OBJECT) {
+ token = jParser.nextToken();
+ }
+ String fetcherName = null;
+ String fetchKey = null;
+ String emitterName = null;
+ String emitKey = null;
+ FetchEmitTuple.ON_PARSE_EXCEPTION onParseException = null;
+ Metadata metadata = new Metadata();
+ while (token != JsonToken.END_OBJECT) {
+ if (token != JsonToken.FIELD_NAME) {
+ throw new IOException("required field name, but see: " + token.name());
+ }
+ String name = jParser.getCurrentName();
+ if (FETCHER.equals(name)) {
+ fetcherName = getValue(jParser);
+ } else if (FETCHKEY.equals(name)) {
+ fetchKey = getValue(jParser);
+ } else if (EMITTER.equals(name)) {
+ emitterName = getValue(jParser);
+ } else if (EMITKEY.equals(name)) {
+ emitKey = getValue(jParser);
+ } else if (METADATAKEY.equals(name)) {
+ token = jParser.nextToken();
+ if (token != JsonToken.START_OBJECT) {
+ throw new IOException("required start object, but see: " + token.name());
+ }
+ metadata = JsonMetadata.readMetadataObject(jParser);
+ } else if (ON_PARSE_EXCEPTION.equals(name)) {
+ String value = getValue(jParser);
+ if ("skip".equalsIgnoreCase(value)) {
+ onParseException = FetchEmitTuple.ON_PARSE_EXCEPTION.SKIP;
+ } else if ("emit".equalsIgnoreCase(value)) {
+ onParseException = FetchEmitTuple.ON_PARSE_EXCEPTION.EMIT;
+ } else {
+ throw new IOException(ON_PARSE_EXCEPTION +
+ " must be either 'skip' or 'emit'");
+ }
+ }
+ token = jParser.nextToken();
+ }
+
+ if (onParseException == null) {
+ return new FetchEmitTuple(
+ new FetchKey(fetcherName, fetchKey),
+ new EmitKey(emitterName, emitKey), metadata
+ );
+ } else {
+ return new FetchEmitTuple(
+ new FetchKey(fetcherName, fetchKey),
+ new EmitKey(emitterName, emitKey), metadata, onParseException
+ );
+ }
+ }
+
+ private static String getValue(JsonParser jParser) throws IOException {
+ JsonToken token = jParser.nextToken();
+ if (token != JsonToken.VALUE_STRING) {
+ throw new IOException("required value string, but see: " + token.name());
+ }
+ return jParser.getValueAsString();
+ }
+
+ public static String toJson(FetchEmitTuple t) throws IOException {
+ StringWriter writer = new StringWriter();
+ toJson(t, writer);
+ return writer.toString();
+ }
+
+ public static void toJson(FetchEmitTuple t, Writer writer) throws IOException {
+
+ try (JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ writeTuple(t, jsonGenerator);
+ }
+ }
+
+ static void writeTuple(FetchEmitTuple t, JsonGenerator jsonGenerator) throws IOException {
+ jsonGenerator.writeStartObject();
+ jsonGenerator.writeStringField(FETCHER, t.getFetchKey().getFetcherName());
+ jsonGenerator.writeStringField(FETCHKEY, t.getFetchKey().getKey());
+ jsonGenerator.writeStringField(EMITTER, t.getEmitKey().getEmitterName());
+ if (!StringUtils.isBlank(t.getEmitKey().getKey())) {
+ jsonGenerator.writeStringField(EMITKEY, t.getEmitKey().getKey());
+ }
+ if (t.getMetadata().size() > 0) {
+ jsonGenerator.writeFieldName(METADATAKEY);
+ JsonMetadata.writeMetadataObject(t.getMetadata(), jsonGenerator, false);
+ }
+ jsonGenerator.writeStringField(ON_PARSE_EXCEPTION,
+ t.getOnParseException().name().toLowerCase(Locale.US));
+ jsonGenerator.writeEndObject();
+
+ }
+}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleList.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleList.java
new file mode 100644
index 0000000..4791aee
--- /dev/null
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleList.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.serialization;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.apache.tika.utils.StringUtils;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JsonFetchEmitTupleList {
+
+ public static List<FetchEmitTuple> fromJson(Reader reader) throws IOException {
+ JsonParser jParser = new JsonFactory().createParser(reader);
+ JsonToken token = jParser.nextToken();
+ if (token != JsonToken.START_ARRAY) {
+ throw new IOException("require start array, but see: "+token.name());
+ }
+ List<FetchEmitTuple> list = new ArrayList<>();
+ while (token != JsonToken.END_ARRAY) {
+ list.add(JsonFetchEmitTuple.parseFetchEmitTuple(jParser));
+ token = jParser.nextToken();
+ }
+ return list;
+ }
+
+ public static String toJson(List<FetchEmitTuple> list) throws IOException {
+ StringWriter writer = new StringWriter();
+ toJson(list, writer);
+ return writer.toString();
+ }
+
+ public static void toJson(List<FetchEmitTuple> list, Writer writer) throws IOException {
+
+ try (JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ jsonGenerator.writeStartArray();
+ for (FetchEmitTuple t : list) {
+ JsonFetchEmitTuple.writeTuple(t, jsonGenerator);
+ }
+ jsonGenerator.writeEndArray();
+ }
+ }
+}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadata.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadata.java
index 50bbbe5..b33c2a9 100644
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadata.java
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.tika.metadata.serialization;
-
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -16,72 +14,130 @@ package org.apache.tika.metadata.serialization;
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.tika.metadata.serialization;
+import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
+import java.util.Arrays;
-import com.google.gson.Gson;
-import com.google.gson.JsonIOException;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
-public class JsonMetadata extends JsonMetadataBase{
- private static Gson GSON;
+public class JsonMetadata {
+
+ static volatile boolean PRETTY_PRINT = false;
- static {
- GSON = defaultInit();
- }
/**
* Serializes a Metadata object to Json. This does not flush or close the writer.
- *
+ *
* @param metadata metadata to write
- * @param writer writer
+ * @param writer writer
* @throws TikaException if there is an IOException during writing
*/
- public static void toJson(Metadata metadata, Writer writer) throws TikaException {
- try {
- GSON.toJson(metadata, writer);
- } catch (JsonIOException e) {
- throw new TikaException(e.getMessage());
+ public static void toJson(Metadata metadata, Writer writer) throws IOException {
+ if (metadata == null) {
+ writer.write("null");
+ return;
+ }
+ try (JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ if (PRETTY_PRINT) {
+ jsonGenerator.useDefaultPrettyPrinter();
+ }
+ writeMetadataObject(metadata, jsonGenerator, PRETTY_PRINT);
}
}
-
+
+ static void writeMetadataObject(Metadata metadata,
+ JsonGenerator jsonGenerator, boolean prettyPrint) throws IOException {
+ jsonGenerator.writeStartObject();
+ String[] names = metadata.names();
+ if (prettyPrint) {
+ Arrays.sort(names, new PrettyMetadataKeyComparator());
+ }
+ for (String n : names) {
+ String[] vals = metadata.getValues(n);
+ if (vals.length == 0) {
+ continue;
+ } else if (vals.length == 1) {
+ jsonGenerator.writeStringField(n, vals[0]);
+ } else if (vals.length > 1) {
+ jsonGenerator.writeArrayFieldStart(n);
+ for (String val : vals) {
+ jsonGenerator.writeString(val);
+ }
+ jsonGenerator.writeEndArray();
+ }
+ }
+ jsonGenerator.writeEndObject();
+ }
+
/**
* Read metadata from reader.
*
* @param reader reader to read from
* @return Metadata or null if nothing could be read from the reader
- * @throws TikaException in case of parse failure by Gson or IO failure with Reader
+ * @throws IOException in case of parse failure or IO failure with Reader
*/
- public static Metadata fromJson(Reader reader) throws TikaException {
+ public static Metadata fromJson(Reader reader) throws IOException {
Metadata m = null;
- try {
- m = GSON.fromJson(reader, Metadata.class);
- } catch (com.google.gson.JsonParseException e){
- //covers both io and parse exceptions
- throw new TikaException(e.getMessage());
+ try (JsonParser jParser = new JsonFactory().createParser(reader)) {
+ m = readMetadataObject(jParser);
}
return m;
}
/**
- * Enables setting custom configurations on Gson. Remember to register
- * a serializer and a deserializer for Metadata. This does a literal set
- * and does not add the default serializer and deserializers.
- *
- * @param gson
+ * expects that jParser has not yet started on object or
+ * for jParser to be pointing to the start object.
+ * @param jParser
+ * @return
+ * @throws IOException
*/
- public static void setGson(Gson gson) {
- GSON = gson;
+ public static Metadata readMetadataObject(JsonParser jParser) throws IOException {
+ Metadata metadata = new Metadata();
+ JsonToken token = jParser.currentToken();
+ if (token == null) {
+ token = jParser.nextToken();
+ if (token != JsonToken.START_OBJECT) {
+ throw new IOException("expected start object, but got: " + token.name());
+ }
+ token = jParser.nextToken();
+ } else if (token == JsonToken.START_OBJECT) {
+ token = jParser.nextToken();
+ }
+
+ while (token != JsonToken.END_OBJECT) {
+ token = jParser.currentToken();
+ if (token != JsonToken.FIELD_NAME) {
+ throw new IOException("expected field name, but got: "
+ + token.name());
+ }
+ String key = jParser.getCurrentName();
+ token = jParser.nextToken();
+ if (token == JsonToken.START_ARRAY) {
+ while (jParser.nextToken() != JsonToken.END_ARRAY) {
+ metadata.add(key, jParser.getText());
+ }
+ } else {
+ if (token != JsonToken.VALUE_STRING) {
+ throw new IOException("expected string value, but found: "+token.name());
+ }
+ String value = jParser.getValueAsString();
+ metadata.set(key, value);
+ }
+ token = jParser.nextToken();
+ }
+ return metadata;
}
public static void setPrettyPrinting(boolean prettyPrint) {
- if (prettyPrint) {
- GSON = prettyInit();
- } else {
- GSON = defaultInit();
- }
+ PRETTY_PRINT = prettyPrint;
}
}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataBase.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataBase.java
deleted file mode 100644
index 90bfca8..0000000
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataBase.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.apache.tika.metadata.serialization;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.util.Arrays;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import org.apache.tika.metadata.Metadata;
-
-public class JsonMetadataBase {
-
-
- static Gson defaultInit() {
- GsonBuilder builder = new GsonBuilder();
- builder.registerTypeHierarchyAdapter(Metadata.class, new JsonMetadataSerializer());
- builder.registerTypeHierarchyAdapter(Metadata.class, new JsonMetadataDeserializer());
- return builder.create();
- }
-
- static Gson prettyInit() {
- GsonBuilder builder = new GsonBuilder();
- builder.registerTypeHierarchyAdapter(Metadata.class, new SortedJsonMetadataSerializer());
- builder.registerTypeHierarchyAdapter(Metadata.class, new JsonMetadataDeserializer());
- builder.setPrettyPrinting();
- return builder.create();
- }
-
- private static class SortedJsonMetadataSerializer extends JsonMetadataSerializer {
- @Override
- public String[] getNames(Metadata m) {
- String[] names = m.names();
- Arrays.sort(names, new PrettyMetadataKeyComparator());
- return names;
- }
- }
-}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataDeserializer.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataDeserializer.java
deleted file mode 100644
index fae0141..0000000
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataDeserializer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.apache.tika.metadata.serialization;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.lang.reflect.Type;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.apache.tika.metadata.Metadata;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
-
-
-/**
- * Deserializer for Metadata
- *
- * If overriding this, remember that this is called from a static context.
- * Share state only with great caution.
- */
-public class JsonMetadataDeserializer implements JsonDeserializer<Metadata> {
-
- /**
- * Deserializes a json object (equivalent to: Map<String, String[]>)
- * into a Metadata object.
- *
- * @param element to serialize
- * @param type (ignored)
- * @param context (ignored)
- * @return Metadata
- * @throws JsonParseException if element is not able to be parsed
- */
- @Override
- public Metadata deserialize(JsonElement element, Type type,
- JsonDeserializationContext context) throws JsonParseException {
-
- final JsonObject obj = element.getAsJsonObject();
- Metadata m = new Metadata();
- for (Map.Entry<String, JsonElement> entry : obj.entrySet()){
- String key = entry.getKey();
- JsonElement v = entry.getValue();
- if (v.isJsonPrimitive()){
- m.set(key, v.getAsString());
- } else if (v.isJsonArray()){
- JsonArray vArr = v.getAsJsonArray();
- for (JsonElement valueItem : vArr) {
- m.add(key, valueItem.getAsString());
- }
-
- }
- }
- return m;
- }
-}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataList.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataList.java
index dea6faf..85f444e 100644
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataList.java
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataList.java
@@ -18,25 +18,23 @@ package org.apache.tika.metadata.serialization;
*/
+import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
-import java.lang.reflect.Type;
+import java.util.ArrayList;
import java.util.List;
-import com.google.gson.Gson;
-import com.google.gson.JsonIOException;
-import com.google.gson.reflect.TypeToken;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
-public class JsonMetadataList extends JsonMetadataBase {
-
- private final static Type listType = new TypeToken<List<Metadata>>(){}.getType();
- private static Gson GSON;
- static {
- GSON = defaultInit();
- }
+public class JsonMetadataList {
+ static volatile boolean PRETTY_PRINT = false;
/**
* Serializes a Metadata object to Json. This does not flush or close the writer.
@@ -45,11 +43,20 @@ public class JsonMetadataList extends JsonMetadataBase {
* @param writer writer
* @throws org.apache.tika.exception.TikaException if there is an IOException during writing
*/
- public static void toJson(List<Metadata> metadataList, Writer writer) throws TikaException {
- try {
- GSON.toJson(metadataList, writer);
- } catch (JsonIOException e) {
- throw new TikaException(e.getMessage());
+ public static void toJson(List<Metadata> metadataList, Writer writer) throws IOException {
+ if (metadataList == null) {
+ writer.write("null");
+ return;
+ }
+ try (JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer)) {
+ if (PRETTY_PRINT) {
+ jsonGenerator.useDefaultPrettyPrinter();
+ }
+ jsonGenerator.writeStartArray();
+ for (Metadata m : metadataList) {
+ JsonMetadata.writeMetadataObject(m, jsonGenerator, PRETTY_PRINT);
+ }
+ jsonGenerator.writeEndArray();
}
}
@@ -58,18 +65,28 @@ public class JsonMetadataList extends JsonMetadataBase {
*
* @param reader
* @return Metadata or null if nothing could be read from the reader
- * @throws org.apache.tika.exception.TikaException in case of parse failure by Gson or IO failure with Reader
+ * @throws IOException in case of parse failure or IO failure with Reader
*/
- public static List<Metadata> fromJson(Reader reader) throws TikaException {
+ public static List<Metadata> fromJson(Reader reader) throws IOException {
List<Metadata> ms = null;
if (reader == null) {
return ms;
}
- try {
- ms = GSON.fromJson(reader, listType);
- } catch (com.google.gson.JsonParseException e){
- //covers both io and parse exceptions
- throw new TikaException(e.getMessage());
+ ms = new ArrayList<>();
+ try (JsonParser jParser = new JsonFactory().createParser(reader)) {
+
+ JsonToken token = jParser.nextToken();
+ if (token != JsonToken.START_ARRAY) {
+ throw new IOException(
+ "metadata list must start with an array, but I see: "+token.name());
+ }
+ token = jParser.nextToken();
+ while (token != JsonToken.END_ARRAY) {
+ Metadata m = JsonMetadata.readMetadataObject(jParser);
+ ms.add(m);
+ token = jParser.nextToken();
+ }
+
}
if (ms == null) {
return null;
@@ -88,23 +105,8 @@ public class JsonMetadataList extends JsonMetadataBase {
return ms;
}
- /**
- * Enables setting custom configurations on Gson. Remember to register
- * a serializer and a deserializer for Metadata. This does a literal set
- * and does not add the default serializer and deserializers.
- *
- * @param gson
- */
- public static void setGson(Gson gson) {
- GSON = gson;
- }
-
public static void setPrettyPrinting(boolean prettyPrint) {
- if (prettyPrint) {
- GSON = prettyInit();
- } else {
- GSON = defaultInit();
- }
+ PRETTY_PRINT = prettyPrint;
}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataSerializer.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataSerializer.java
deleted file mode 100644
index 602c346..0000000
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonMetadataSerializer.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.apache.tika.metadata.serialization;
-
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements. See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-import java.lang.reflect.Type;
-import java.util.Arrays;
-
-import org.apache.tika.metadata.Metadata;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonNull;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-
-
-/**
- * Serializer for Metadata
- *
- * If overriding this, remember that this is called from a static context.
- * Share state only with great caution.
- *
- */
-public class JsonMetadataSerializer implements JsonSerializer<Metadata> {
-
-
- /**
- * Serializes a Metadata object into effectively Map<String, String[]>.
- *
- * @param metadata object to serialize
- * @param type (ignored)
- * @param context (ignored)
- * @return JsonElement with key/value(s) pairs or JsonNull if metadata is null.
- */
- @Override
- public JsonElement serialize(Metadata metadata, Type type, JsonSerializationContext context) {
- if (metadata == null){
- return JsonNull.INSTANCE;
- }
- String[] names = getNames(metadata);
- if (names == null) {
- return JsonNull.INSTANCE;
- }
-
- JsonObject root = new JsonObject();
-
- for (String n : names) {
-
- String[] vals = metadata.getValues(n);
- if (vals == null) {
- //silently skip
- continue;
- }
-
- if (vals.length == 1){
- root.addProperty(n, vals[0]);
- } else {
- JsonArray jArr = new JsonArray();
- for (String val : vals) {
- jArr.add(new JsonPrimitive(val));
- }
- root.add(n, jArr);
- }
- }
- return root;
- }
-
- /**
- * Override to get a custom sort order
- * or to filter names.
- *
- * @param metadata metadata from which to grab names
- * @return list of names in the order in which they should be serialized
- */
- protected String[] getNames(Metadata metadata) {
- String[] names = metadata.names();
- Arrays.sort(names);
- return names;
- }
-}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonStreamingSerializer.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonStreamingSerializer.java
index f01df6f..fb29a5e 100644
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonStreamingSerializer.java
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/JsonStreamingSerializer.java
@@ -16,7 +16,9 @@
*/
package org.apache.tika.metadata.serialization;
-import com.google.gson.stream.JsonWriter;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
import org.apache.tika.metadata.Metadata;
import java.io.IOException;
@@ -26,40 +28,28 @@ import java.util.Arrays;
public class JsonStreamingSerializer implements AutoCloseable {
- private final JsonWriter jsonWriter;
+ private final Writer writer;
+ private JsonGenerator jsonGenerator;
boolean hasStartedArray = false;
public JsonStreamingSerializer(Writer writer) {
- this.jsonWriter = new JsonWriter(writer);
+ this.writer = writer;
}
public void add(Metadata metadata) throws IOException {
if (!hasStartedArray) {
- jsonWriter.beginArray();
+ jsonGenerator = new JsonFactory().createGenerator(writer);
+ jsonGenerator.writeStartArray();
hasStartedArray = true;
}
String[] names = metadata.names();
Arrays.sort(names);
- jsonWriter.beginObject();
- for (String n : names) {
- jsonWriter.name(n);
- String[] values = metadata.getValues(n);
- if (values.length == 1) {
- jsonWriter.value(values[0]);
- } else {
- jsonWriter.beginArray();
- for (String v : values) {
- jsonWriter.value(v);
- }
- jsonWriter.endArray();
- }
- }
- jsonWriter.endObject();
+ JsonMetadata.writeMetadataObject(metadata, jsonGenerator, false);
}
@Override
public void close() throws IOException {
- jsonWriter.endArray();
- jsonWriter.flush();
- jsonWriter.close();
+ jsonGenerator.writeEndArray();
+ jsonGenerator.flush();
+ jsonGenerator.close();
}
}
diff --git a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/PrettyMetadataKeyComparator.java b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/PrettyMetadataKeyComparator.java
index 5516c1d..35e76b7 100644
--- a/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/PrettyMetadataKeyComparator.java
+++ b/tika-serialization/src/main/java/org/apache/tika/metadata/serialization/PrettyMetadataKeyComparator.java
@@ -17,6 +17,8 @@ package org.apache.tika.metadata.serialization;
* limitations under the License.
*/
+import org.apache.tika.metadata.TikaCoreProperties;
+
public class PrettyMetadataKeyComparator implements java.util.Comparator<String> {
@Override
public int compare(String s1, String s2) {
@@ -26,15 +28,12 @@ public class PrettyMetadataKeyComparator implements java.util.Comparator<String>
return -1;
}
- //this is stinky. This should reference AbstractRecursiveParserWrapperHandler.TIKA_CONTENT
- //but that would require making core a dependency of serialization...
- //do we want to do that?
- if (s1.equals("tika:content")) {
- if (s2.equals("tika:content")) {
+ if (s1.equals(TikaCoreProperties.TIKA_CONTENT.getName())) {
+ if (s2.equals(TikaCoreProperties.TIKA_CONTENT.getName())) {
return 0;
}
return 2;
- } else if (s2.equals("tika:content")) {
+ } else if (s2.equals(TikaCoreProperties.TIKA_CONTENT.getName())) {
return -2;
}
//do we want to lowercase?
diff --git a/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleListTest.java b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleListTest.java
new file mode 100644
index 0000000..80c37f4
--- /dev/null
+++ b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleListTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.serialization;
+
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.junit.Test;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class JsonFetchEmitTupleListTest {
+
+ @Test
+ public void testBasic() throws Exception {
+ List<FetchEmitTuple> list = new ArrayList<>();
+ for (int i = 0; i < 57; i++) {
+ list.add(getFetchEmitTuple(i));
+ }
+ StringWriter writer = new StringWriter();
+ JsonFetchEmitTupleList.toJson(list, writer);
+
+ Reader reader = new StringReader(writer.toString());
+ List<FetchEmitTuple> deserialized = JsonFetchEmitTupleList.fromJson(reader);
+ assertEquals(list, deserialized);
+ }
+
+ private FetchEmitTuple getFetchEmitTuple(int i) {
+ Metadata m = new Metadata();
+ m.add("m1", "v1-"+i);
+ m.add("m1", "v1-"+i);
+ m.add("m2", "v2-"+i);
+ m.add("m2", "v3-"+i);
+ m.add("m3", "v4-"+i);
+
+ return new FetchEmitTuple(
+ new FetchKey("fetcher-"+i, "fetchkey-"+i),
+ new EmitKey("emitter-"+i, "emitKey-"+i),
+ m);
+ }
+}
diff --git a/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleTest.java b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleTest.java
new file mode 100644
index 0000000..67bbbde
--- /dev/null
+++ b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonFetchEmitTupleTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.serialization;
+
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.junit.Test;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import static org.junit.Assert.assertEquals;
+
+public class JsonFetchEmitTupleTest {
+
+ @Test
+ public void testBasic() throws Exception {
+ Metadata m = new Metadata();
+ m.add("m1", "v1");
+ m.add("m1", "v1");
+ m.add("m2", "v2");
+ m.add("m2", "v3");
+ m.add("m3", "v4");
+
+ FetchEmitTuple t = new FetchEmitTuple(
+ new FetchKey("fetcher1", "fetchkey1"),
+ new EmitKey("emitter1", "emitKey1"),
+ m);
+ StringWriter writer = new StringWriter();
+ JsonFetchEmitTuple.toJson(t, writer);
+
+ Reader reader = new StringReader(writer.toString());
+ FetchEmitTuple deserialized = JsonFetchEmitTuple.fromJson(reader);
+ assertEquals(t, deserialized);
+ }
+}
diff --git a/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataListTest.java b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataListTest.java
index 522807e..543bbcd 100644
--- a/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataListTest.java
+++ b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataListTest.java
@@ -93,7 +93,7 @@ public class JsonMetadataListTest {
@Test
public void testPrettyPrint() throws Exception {
Metadata m1 = new Metadata();
- m1.add("tika:content", "this is the content");
+ m1.add(TikaCoreProperties.TIKA_CONTENT, "this is the content");
m1.add("zk1", "v1");
m1.add("zk1", "v2");
m1.add("zk1", "v3");
@@ -114,24 +114,22 @@ public class JsonMetadataListTest {
metadataList.add(m2);
StringWriter writer = new StringWriter();
JsonMetadataList.toJson(metadataList, writer);
- assertTrue(writer.toString().startsWith("[{\"tika:content\":\"this is the content\",\"zk1\":[\"v1\",\"v2\","));
+ assertTrue(writer.toString().startsWith("["));
writer = new StringWriter();
JsonMetadataList.setPrettyPrinting(true);
JsonMetadataList.toJson(metadataList, writer);
- assertTrue(writer.toString().startsWith("[\n" +
- " {\n" +
- " \"zk1\": [\n" +
- " \"v1\",\n" +
- " \"v2\","));
- assertTrue(writer.toString().contains(" \"zk2\": \"v1\",\n" +
- " \"tika:content\": \"this is the content\"\n" +
- " },"));
+ assertTrue(writer.toString().startsWith("[ {\n" +
+ " \"zk1\" : [ \"v1\", \"v2\", \"v3\", \"v4\", \"v4\" ],\n" +
+ " \"zk2\" : \"v1\",\n" +
+ " \"X-TIKA:content\" : \"this is the content\"\n" +
+ "},"));
+
//now set it back to false
JsonMetadataList.setPrettyPrinting(false);
writer = new StringWriter();
JsonMetadataList.toJson(metadataList, writer);
- assertTrue(writer.toString().startsWith("[{\"tika:content\":\"this is the content\",\"zk1\":[\"v1\",\"v2\","));
+ assertTrue(writer.toString().startsWith("["));
}
@Test
diff --git a/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataTest.java b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataTest.java
index 4cf5367..3abeaa6 100644
--- a/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataTest.java
+++ b/tika-serialization/src/test/java/org/apache/tika/metadata/serialization/JsonMetadataTest.java
@@ -17,6 +17,7 @@ package org.apache.tika.metadata.serialization;
* limitations under the License.
*/
+import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
@@ -63,18 +64,12 @@ public class JsonMetadataTest {
JsonMetadata.setPrettyPrinting(true);
JsonMetadata.toJson(metadata, writer);
assertTrue(writer.toString().contains(
- " \"json_escapes\": \"the: \\\"quick\\\" brown, fox\",\n" +
- " \"k1\": [\n" +
- " \"v1\",\n" +
- " \"v2\"\n" +
- " ],\n" +
- " \"k3\": [\n" +
- " \"v3\",\n" +
- " \"v3\"\n" +
- " ],\n" +
- " \"k4\": \"500,000\",\n" +
- " \"url\": \"/myApp/myAction.html?method\\u003drouter\\u0026cmd\\u003d1\"\n" +
- "}"));
+ "\"json_escapes\" : \"the: \\\"quick\\\" brown, fox\",\n" +
+ " \"k1\" : [ \"v1\", \"v2\" ],\n" +
+ " \"k3\" : [ \"v3\", \"v3\" ],\n" +
+ " \"k4\" : \"500,000\",\n" +
+ " \"url\" : \"/myApp/myAction.html?method=router&cmd=1\"\n" +
+ "}"));
}
@Test
@@ -84,7 +79,7 @@ public class JsonMetadataTest {
boolean ex = false;
try {
Metadata deserialized = JsonMetadata.fromJson(new StringReader(json));
- } catch (TikaException e) {
+ } catch (IOException e) {
ex = true;
}
assertTrue(ex);
@@ -96,7 +91,7 @@ public class JsonMetadataTest {
boolean ex = false;
try {
JsonMetadata.toJson(null, writer);
- } catch (TikaException e) {
+ } catch (IOException e) {
ex = true;
}
assertFalse(ex);
diff --git a/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaDetectorsTest.java b/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaDetectorsTest.java
index 8d78ba5..dd5fd5c 100644
--- a/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaDetectorsTest.java
+++ b/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaDetectorsTest.java
@@ -26,8 +26,8 @@ import java.io.InputStream;
import java.util.List;
import java.util.Map;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
@@ -42,9 +42,6 @@ import org.junit.Test;
public class TikaDetectorsTest extends CXFTestBase {
- private static final Gson GSON = new GsonBuilder().create();
-
-
private static final String DETECTORS_PATH = "/detectors";
@Override
@@ -108,7 +105,8 @@ public class TikaDetectorsTest extends CXFTestBase {
.get();
String jsonStr = getStringFromInputStream((InputStream) response.getEntity());
- Map<String, Object> json = (Map<String, Object>) GSON.fromJson(jsonStr, Map.class);
+ Map<String, Object> json =
+ new ObjectMapper().readerFor(Map.class).readValue(jsonStr);
// Should have a nested structure
assertTrue(json.containsKey("name"));
diff --git a/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaMimeTypesTest.java b/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaMimeTypesTest.java
index 028c68c..b727176 100644
--- a/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaMimeTypesTest.java
+++ b/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaMimeTypesTest.java
@@ -16,8 +16,8 @@
*/
package org.apache.tika.server.classic;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
@@ -34,7 +34,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class TikaMimeTypesTest extends CXFTestBase {
- private static final Gson GSON = new GsonBuilder().create();
private static final String MIMETYPES_PATH = "/mime-types";
@@ -62,8 +61,7 @@ public class TikaMimeTypesTest extends CXFTestBase {
.get();
String jsonStr = getStringFromInputStream((InputStream) response.getEntity());
- Map<String, Map<String, Object>> json = (Map<String, Map<String, Object>>)
- GSON.fromJson(jsonStr, Map.class);
+ Map<String, Map<String, Object>> json = new ObjectMapper().readerFor(Map.class).readValue(jsonStr);
assertEquals(true, json.containsKey("text/plain"));
assertEquals(true, json.containsKey("application/xml"));
diff --git a/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaParsersTest.java b/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaParsersTest.java
index 9b065e5..771cca6 100644
--- a/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaParsersTest.java
+++ b/tika-server/tika-server-classic/src/test/java/org/apache/tika/server/classic/TikaParsersTest.java
@@ -26,8 +26,7 @@ import java.io.InputStream;
import java.util.List;
import java.util.Map;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
@@ -40,8 +39,6 @@ import org.junit.Test;
public class TikaParsersTest extends CXFTestBase {
- private static final Gson GSON = new GsonBuilder().create();
-
private static final String PARSERS_SUMMARY_PATH = "/parsers";
private static final String PARSERS_DETAILS_PATH = "/parsers/details";
@@ -142,8 +139,8 @@ public class TikaParsersTest extends CXFTestBase {
.get();
String jsonStr = getStringFromInputStream((InputStream) response.getEntity());
- Map<String, Map<String, Object>> json = (Map<String, Map<String, Object>>)
- GSON.fromJson(jsonStr, Map.class);
+ Map<String, Map<String, Object>> json =
+ new ObjectMapper().readerFor(Map.class).readValue(jsonStr);
// Should have a nested structure
assertEquals(true, json.containsKey("name"));
diff --git a/tika-server/tika-server-client/pom.xml b/tika-server/tika-server-client/pom.xml
index d3daf68..920b644 100644
--- a/tika-server/tika-server-client/pom.xml
+++ b/tika-server/tika-server-client/pom.xml
@@ -32,16 +32,16 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tika-serialization</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpcomponents.version}</version>
</dependency>
<dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <version>${gson.version}</version>
- </dependency>
- <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
diff --git a/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClient.java b/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClient.java
index 6e0e26e..336cb7d 100644
--- a/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClient.java
+++ b/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClient.java
@@ -16,27 +16,21 @@
*/
package org.apache.tika.server.client;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.exception.TikaException;
-import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTuple;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTupleList;
import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
import java.io.IOException;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TikaClient {
- private static final Gson GSON = new GsonBuilder().create();
-
private final Random random = new Random();
- private final TikaConfig tikaConfig;
private List<TikaHttpClient> clients;
@@ -45,11 +39,11 @@ public class TikaClient {
for (String url : tikaServers) {
clients.add(TikaHttpClient.get(url));
}
- return new TikaClient(tikaConfig, clients);
+ return new TikaClient(clients);
}
- private TikaClient(TikaConfig tikaConfig, List<TikaHttpClient> clients) {
- this.tikaConfig = tikaConfig;
+ private TikaClient(List<TikaHttpClient> clients) {
+
this.clients = clients;
}
@@ -57,37 +51,20 @@ public class TikaClient {
}*/
- public TikaEmitterResult parse(FetchEmitTuple fetchEmit, Metadata metadata)
+ public TikaEmitterResult parse(FetchEmitTuple fetchEmit)
throws IOException, TikaException {
TikaHttpClient client = getHttpClient();
- String jsonRequest = jsonifyRequest(fetchEmit, metadata);
- return client.postJson(jsonRequest);
-
+ StringWriter writer = new StringWriter();
+ JsonFetchEmitTuple.toJson(fetchEmit, writer);
+ return client.postJson(writer.toString());
}
- private String jsonifyRequest(FetchEmitTuple fetchEmit, Metadata metadata) {
- JsonObject root = new JsonObject();
- root.add("fetcher", new JsonPrimitive(fetchEmit.getFetchKey().getFetcherName()));
- root.add("fetchKey", new JsonPrimitive(fetchEmit.getFetchKey().getKey()));
- root.add("emitter", new JsonPrimitive(fetchEmit.getEmitKey().getEmitterName()));
- root.add("emitKey", new JsonPrimitive(fetchEmit.getEmitKey().getEmitKey()));
- if (metadata.size() > 0) {
- JsonObject m = new JsonObject();
- for (String n : metadata.names()) {
- String[] vals = metadata.getValues(n);
- if (vals.length == 1) {
- m.add(n, new JsonPrimitive(vals[0]));
- } else if (vals.length > 1) {
- JsonArray arr = new JsonArray();
- for (int i = 0; i < vals.length; i++) {
- arr.add(vals[i]);
- }
- m.add(n, arr);
- }
- }
- root.add("metadata", m);
- }
- return GSON.toJson(root);
+ public TikaEmitterResult parseAsync(List<FetchEmitTuple> tuples)
+ throws IOException, TikaException {
+ StringWriter writer = new StringWriter();
+ JsonFetchEmitTupleList.toJson(tuples, writer);
+ TikaHttpClient client = getHttpClient();
+ return client.postJsonAsync(writer.toString());
}
private TikaHttpClient getHttpClient() {
diff --git a/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClientCLI.java b/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClientCLI.java
index 4b438e2..d760ab9 100644
--- a/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClientCLI.java
+++ b/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaClientCLI.java
@@ -27,6 +27,7 @@ import org.xml.sax.SAXException;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -108,6 +109,42 @@ public class TikaClientCLI {
servers, numThreads);
}
+ private class AsyncFetchWorker implements Callable<Integer> {
+ private final ArrayBlockingQueue<FetchEmitTuple> queue;
+ private final TikaClient client;
+ public AsyncFetchWorker(ArrayBlockingQueue<FetchEmitTuple> queue, TikaClient client) {
+ this.queue = queue;
+ this.client = client;
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ List<FetchEmitTuple> localCache = new ArrayList<>();
+ while (true) {
+
+ FetchEmitTuple t = queue.poll(maxWaitMs, TimeUnit.MILLISECONDS);
+ if (t == null) {
+ send(localCache);
+ throw new TimeoutException("exceeded maxWaitMs");
+ }
+ if (t == FetchIterator.COMPLETED_SEMAPHORE) {
+ send(localCache);
+ return 1;
+ }
+ if (localCache.size() > 20) {
+ LOGGER.debug("about to send: {}", localCache.size());
+ send(localCache);
+ localCache.clear();
+ }
+ localCache.add(t);
+ }
+ }
+
+ private void send(List<FetchEmitTuple> localCache) {
+
+ }
+ }
+
private class FetchWorker implements Callable<Integer> {
private final ArrayBlockingQueue<FetchEmitTuple> queue;
private final TikaClient client;
@@ -130,7 +167,7 @@ public class TikaClientCLI {
}
try {
LOGGER.debug("about to parse: {}", t.getFetchKey());
- client.parse(t, t.getMetadata());
+ client.parse(t);
} catch (IOException e) {
LOGGER.warn(t.getFetchKey().toString(), e);
} catch (TikaException e) {
diff --git a/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaHttpClient.java b/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaHttpClient.java
index 621f5db..591064a 100644
--- a/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaHttpClient.java
+++ b/tika-server/tika-server-client/src/main/java/org/apache/tika/server/client/TikaHttpClient.java
@@ -18,7 +18,6 @@ package org.apache.tika.server.client;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
@@ -26,6 +25,7 @@ import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.tika.exception.TikaException;
+import org.apache.tika.pipes.emitter.TikaEmitterException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,12 +39,14 @@ import java.nio.charset.StandardCharsets;
*/
class TikaHttpClient {
- private static final String ENDPOINT = "emit";
+ private static final String EMIT_ENDPOINT = "emit";
private static final String TIKA_ENDPOINT = "tika";
+ private static final String ASYNC_ENDPOINT = "async";
private static final Logger LOGGER = LoggerFactory.getLogger(TikaHttpClient.class);
private final HttpHost httpHost;
private final HttpClient httpClient;
- private final String endPointUrl;
+ private final String emitEndPointUrl;
+ private final String asyncEndPointUrl;
private final String tikaUrl;
private int maxRetries = 3;
//if can't make contact with Tika server, max wait time in ms
@@ -53,38 +55,46 @@ class TikaHttpClient {
private long pulseWaitForTikaMs = 1000;
static TikaHttpClient get(String baseUrl) throws TikaClientConfigException {
- String endPointUrl = baseUrl.endsWith("/") ? baseUrl+ENDPOINT : baseUrl+"/"+ENDPOINT;
- String tikaUrl = baseUrl.endsWith("/") ? baseUrl+TIKA_ENDPOINT : baseUrl+"/"+TIKA_ENDPOINT;
URI uri;
try {
- uri = new URI(endPointUrl);
+ uri = new URI(baseUrl);
} catch (URISyntaxException e) {
throw new TikaClientConfigException("bad URI", e);
}
HttpHost httpHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
//TODO: need to add other configuration stuff? proxy, username, password, timeouts...
HttpClient client = HttpClients.createDefault();
- return new TikaHttpClient(endPointUrl, tikaUrl, httpHost, client);
+ return new TikaHttpClient(baseUrl, httpHost, client);
}
/**
*
- * @param endPointUrl full url to the tika-server including endpoint
- * @param tikaUrl url to /tika endpoint to use to check on server status
+ * @param baseUrl url to base endpoint
* @param httpHost
* @param httpClient
*/
- private TikaHttpClient(String endPointUrl, String tikaUrl, HttpHost httpHost, HttpClient httpClient) {
- this.endPointUrl = endPointUrl;
- this.tikaUrl = tikaUrl;
+ private TikaHttpClient(String baseUrl, HttpHost httpHost, HttpClient httpClient) {
+ if (! baseUrl.endsWith("/")) {
+ baseUrl += "/";
+ }
+ this.emitEndPointUrl = baseUrl+EMIT_ENDPOINT;
+ this.asyncEndPointUrl = baseUrl+ASYNC_ENDPOINT;
+ this.tikaUrl = baseUrl+TIKA_ENDPOINT;
this.httpHost = httpHost;
this.httpClient = httpClient;
}
+ public TikaEmitterResult postJsonAsync(String jsonRequest) {
+ return postJson(asyncEndPointUrl, jsonRequest);
+ }
public TikaEmitterResult postJson(String jsonRequest) {
- System.out.println("NED:"+endPointUrl);
- HttpPost post = new HttpPost(endPointUrl);
+ return postJson(emitEndPointUrl, jsonRequest);
+ }
+
+ private TikaEmitterResult postJson(String endPoint, String jsonRequest) {
+ System.out.println("NED:"+endPoint);
+ HttpPost post = new HttpPost(endPoint);
ByteArrayEntity entity = new ByteArrayEntity(jsonRequest.getBytes(StandardCharsets.UTF_8));
post.setEntity(entity);
post.setHeader("Content-Type", "application/json");
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatus.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatus.java
index a15f7a5..92068f5 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatus.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatus.java
@@ -41,7 +41,7 @@ public class ServerStatus {
public enum STATUS {
INITIALIZING(0),
OPERATING(1),
- HIT_MAX(2),
+ HIT_MAX_FILES(2),
TIMEOUT(3),
ERROR(4),
PARENT_REQUESTED_SHUTDOWN(5),
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatusWatcher.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatusWatcher.java
index a2ad313..7ac0ffd 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatusWatcher.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/ServerStatusWatcher.java
@@ -136,7 +136,7 @@ public class ServerStatusWatcher implements Runnable {
}
long filesProcessed = serverStatus.getFilesProcessed();
if (filesProcessed >= maxFiles) {
- serverStatus.setStatus(ServerStatus.STATUS.HIT_MAX);
+ serverStatus.setStatus(ServerStatus.STATUS.HIT_MAX_FILES);
}
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerCli.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerCli.java
index dbcbeb1..14a2ff4 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerCli.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerCli.java
@@ -140,6 +140,7 @@ public class TikaServerCli {
try {
mainLoop(line, newArgs);
} catch (InterruptedException e) {
+ e.printStackTrace();
//swallow
}
}
@@ -173,11 +174,13 @@ public class TikaServerCli {
WatchDogResult result = future.get();
LOG.debug("main loop future: ({}); about to restart", result);
if (maxRestarts < 0 || result.getNumRestarts() < maxRestarts) {
+ System.err.println("starting up again");
executorCompletionService.submit(
new TikaServerWatchDog(args, result.getPort(),
result.getId(),
result.getNumRestarts(), serverTimeoutConfig));
} else {
+ System.err.println("finished!");
LOG.warn("id {} with port {} has exceeded maxRestarts {}. Shutting down and not restarting.",
result.getId(), result.getPort(), maxRestarts);
finished++;
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerProcess.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerProcess.java
index 0a8fd91..5135f55 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerProcess.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerProcess.java
@@ -23,6 +23,7 @@ import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.cxf.binding.BindingFactoryManager;
+import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSBindingFactory;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
@@ -36,6 +37,11 @@ import org.apache.tika.config.TikaConfig;
import org.apache.tika.parser.DigestingParser;
import org.apache.tika.parser.digestutils.BouncyCastleDigester;
import org.apache.tika.parser.digestutils.CommonsDigester;
+import org.apache.tika.pipes.emitter.EmitData;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.apache.tika.server.core.resource.AsyncEmitter;
+import org.apache.tika.server.core.resource.AsyncParser;
+import org.apache.tika.server.core.resource.AsyncResource;
import org.apache.tika.server.core.resource.DetectorResource;
import org.apache.tika.server.core.resource.EmitterResource;
import org.apache.tika.server.core.resource.LanguageResource;
@@ -72,13 +78,20 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
public class TikaServerProcess {
//used in fork mode -- restart after processing this many files
private static final long DEFAULT_MAX_FILES = 100000;
-
+ private static String ENABLE_UNSECURE_FEATURES = "enableUnsecureFeatures";
private static final int DEFAULT_DIGEST_MARK_LIMIT = 20 * 1024 * 1024;
public static final Set<String> LOG_LEVELS = new HashSet<>(Arrays.asList("debug", "info"));
@@ -129,10 +142,9 @@ public class TikaServerProcess {
LOG.info("Starting {} server", new Tika());
try {
Options options = getOptions();
-
CommandLineParser cliParser = new DefaultParser();
CommandLine line = cliParser.parse(options, args);
- runServer(line, options);
+ mainLoop(line, options);
} catch (Exception e) {
e.printStackTrace();
LOG.error("Can't start: ", e);
@@ -140,11 +152,44 @@ public class TikaServerProcess {
}
}
- //This starts the server in this process. This can
- //be either a direct call from -noFork or the process that is forked
- //in the 2.0 default mode.
- private static void runServer(CommandLine line, Options options) throws Exception {
+ private static void mainLoop(CommandLine commandLine, Options options) throws Exception {
+ AsyncResource asyncResource = null;
+ ArrayBlockingQueue<FetchEmitTuple> asyncFetchEmitQueue = null;
+ ArrayBlockingQueue<EmitData> asyncEmitData = null;
+ int numAsyncParserThreads = 10;
+ if (commandLine.hasOption(ENABLE_UNSECURE_FEATURES)) {
+ asyncResource = new AsyncResource();
+ asyncFetchEmitQueue = asyncResource.getFetchEmitQueue(10000);
+ asyncEmitData = asyncResource.getEmitDataQueue(1000);
+ }
+
+ ServerDetails serverDetails = initServer(commandLine, asyncResource);
+ ExecutorService executorService = Executors.newFixedThreadPool(numAsyncParserThreads+1);
+ ExecutorCompletionService<Integer> executorCompletionService = new ExecutorCompletionService<>(executorService);
+
+ if (asyncFetchEmitQueue != null) {
+ executorCompletionService.submit(new AsyncEmitter(asyncEmitData));
+ for (int i = 0; i < numAsyncParserThreads; i++) {
+ executorCompletionService.submit(new AsyncParser(asyncFetchEmitQueue, asyncEmitData));
+ }
+ }
+ //start the server
+ Server server = serverDetails.sf.create();
+ LOG.info("Started Apache Tika server {} at {}",
+ serverDetails.serverId,
+ serverDetails.url);
+
+ while (true) {
+ Future<Integer> future = executorCompletionService.poll(1, TimeUnit.MINUTES);
+ if (future != null) {
+ LOG.warn("future val: " + future.get());
+ }
+ }
+ }
+ //This returns the server, configured and ready to be started.
+ private static ServerDetails initServer(CommandLine line,
+ AsyncResource asyncResource) throws Exception {
String host = null;
if (line.hasOption("host")) {
@@ -224,12 +269,12 @@ public class TikaServerProcess {
}
InputStreamFactory inputStreamFactory = null;
- if (line.hasOption("enableUnsecureFeatures")) {
+ if (line.hasOption(ENABLE_UNSECURE_FEATURES)) {
inputStreamFactory = new FetcherStreamFactory(tika.getFetcherManager());
} else {
inputStreamFactory = new DefaultInputStreamFactory();
}
- logFetchersAndEmitters(line.hasOption("enableUnsecureFeatures"), tika);
+ logFetchersAndEmitters(line.hasOption(ENABLE_UNSECURE_FEATURES), tika);
String serverId = line.hasOption("i") ? line.getOptionValue("i") : UUID.randomUUID().toString();
LOG.debug("SERVER ID:" + serverId);
ServerStatus serverStatus;
@@ -272,8 +317,9 @@ public class TikaServerProcess {
rCoreProviders.add(new SingletonResourceProvider(new TikaDetectors()));
rCoreProviders.add(new SingletonResourceProvider(new TikaParsers()));
rCoreProviders.add(new SingletonResourceProvider(new TikaVersion()));
- if (line.hasOption("enableUnsecureFeatures")) {
+ if (line.hasOption(ENABLE_UNSECURE_FEATURES)) {
rCoreProviders.add(new SingletonResourceProvider(new EmitterResource()));
+ rCoreProviders.add(new SingletonResourceProvider(asyncResource));
}
rCoreProviders.addAll(loadResourceServices());
if (line.hasOption("status")) {
@@ -315,11 +361,11 @@ public class TikaServerProcess {
JAXRSBindingFactory factory = new JAXRSBindingFactory();
factory.setBus(sf.getBus());
manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, factory);
- sf.create();
- LOG.info("Started Apache Tika server {} at {}",
- serverId,
- url);
-
+ ServerDetails details = new ServerDetails();
+ details.sf = sf;
+ details.url = url;
+ details.serverId = serverId;
+ return details;
}
private static void logFetchersAndEmitters(boolean enableUnsecureFeatures, TikaConfig tika) {
@@ -421,4 +467,10 @@ public class TikaServerProcess {
return serverTimeouts;
}
+
+ private static class ServerDetails {
+ JAXRSServerFactoryBean sf;
+ String serverId;
+ String url;
+ }
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncEmitter.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncEmitter.java
new file mode 100644
index 0000000..315927a
--- /dev/null
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncEmitter.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.server.core.resource;
+
+import org.apache.tika.pipes.emitter.AbstractEmitter;
+import org.apache.tika.pipes.emitter.EmitData;
+import org.apache.tika.pipes.emitter.Emitter;
+import org.apache.tika.pipes.emitter.TikaEmitterException;
+import org.apache.tika.utils.ExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Worker thread that takes EmitData off the queue, batches it
+ * and tries to emit it as a batch
+ */
+public class AsyncEmitter implements Callable<Integer> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AsyncEmitter.class);
+
+ //TODO -- need to configure these
+ private final long emitWithinMs = 1000;
+
+ private long maxEstimatedBytes = 10_000_000;
+
+ private final ArrayBlockingQueue<EmitData> emitDataQueue;
+
+ Instant lastEmitted = Instant.now();
+
+ public AsyncEmitter(ArrayBlockingQueue<EmitData> emitData) {
+ this.emitDataQueue = emitData;
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ EmitDataCache cache = new EmitDataCache(maxEstimatedBytes);
+
+ while (true) {
+ EmitData emitData = emitDataQueue.poll(100, TimeUnit.MILLISECONDS);
+ if (emitData != null) {
+ //this can block on emitAll
+ cache.add(emitData);
+ } else {
+ LOG.trace("Nothing on the async queue");
+ }
+ LOG.debug("cache size: ({}) bytes and count: {}",
+ cache.estimatedSize, cache.size);
+ long elapsed = ChronoUnit.MILLIS.between(lastEmitted, Instant.now());
+ if (elapsed > emitWithinMs) {
+ LOG.debug("{} elapsed > {}, going to emitAll",
+ elapsed, emitWithinMs);
+ //this can block
+ cache.emitAll();
+ }
+ }
+ }
+
+ private class EmitDataCache {
+ private final long maxBytes;
+
+ long estimatedSize = 0;
+ int size = 0;
+ Map<String, List<EmitData>> map = new HashMap<>();
+
+ public EmitDataCache(long maxBytes) {
+ this.maxBytes = maxBytes;
+ }
+
+ void updateEstimatedSize(long newBytes) {
+ estimatedSize += newBytes;
+ }
+
+ void add(EmitData data) {
+ size++;
+ long sz = AbstractEmitter.estimateSizeInBytes(data.getEmitKey().getKey(), data.getMetadataList());
+ if (estimatedSize + sz > maxBytes) {
+ LOG.debug("estimated size ({}) > maxBytes({}), going to emitAll",
+ (estimatedSize+sz), maxBytes);
+ emitAll();
+ }
+ List<EmitData> cached = map.get(data.getEmitKey().getEmitterName());
+ if (cached == null) {
+ cached = new ArrayList<>();
+ map.put(data.getEmitKey().getEmitterName(), cached);
+ }
+ updateEstimatedSize(sz);
+ cached.add(data);
+ }
+
+ private void emitAll() {
+ int emitted = 0;
+ LOG.debug("about to emit {}", size);
+ for (Map.Entry<String, List<EmitData>> e : map.entrySet()) {
+ Emitter emitter = TikaResource.getConfig()
+ .getEmitterManager().getEmitter(e.getKey());
+ tryToEmit(emitter, e.getValue());
+ emitted += e.getValue().size();
+ }
+ LOG.debug("emitted: {}", emitted);
+ estimatedSize = 0;
+ size = 0;
+ map.clear();
+ lastEmitted = Instant.now();
+ }
+
+ private void tryToEmit(Emitter emitter, List<EmitData> cachedEmitData) {
+
+ try {
+ emitter.emit(cachedEmitData);
+ } catch (IOException|TikaEmitterException e) {
+ LOG.warn("emitter class ({}): {}", emitter.getClass(),
+ ExceptionUtils.getStackTrace(e));
+ }
+ }
+ }
+}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncParser.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncParser.java
new file mode 100644
index 0000000..c20fc75
--- /dev/null
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncParser.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.server.core.resource;
+
+import org.apache.cxf.jaxrs.impl.UriInfoImpl;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.pipes.emitter.EmitData;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.apache.tika.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import java.io.InputStream;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Worker thread that takes {@link FetchEmitTuple} off the queue, parses
+ * the file and puts the {@link EmitData} on the emitDataQueue for the {@link AsyncEmitter}.
+ *
+ */
+public class AsyncParser implements Callable<Integer> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AsyncParser.class);
+
+ private final ArrayBlockingQueue<FetchEmitTuple> fetchEmitTupleQueue;
+ private final ArrayBlockingQueue<EmitData> emitDataQueue;
+
+ public AsyncParser(ArrayBlockingQueue<FetchEmitTuple> queue,
+ ArrayBlockingQueue<EmitData> emitData) {
+ this.fetchEmitTupleQueue = queue;
+ this.emitDataQueue = emitData;
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ while (true) {
+ FetchEmitTuple request = fetchEmitTupleQueue.poll(1, TimeUnit.MINUTES);
+ if (request != null) {
+ EmitData emitData = processTuple(request);
+ boolean shouldEmit = checkForParseException(request, emitData);
+ if (shouldEmit) {
+ boolean offered = emitDataQueue.offer(emitData, 10, TimeUnit.MINUTES);
+ if (!offered) {
+ //TODO: deal with this
+ LOG.warn("Failed to add ({}) " +
+ "to emit queue after 10 minutes.",
+ request.getFetchKey().getKey());
+ }
+ }
+ } else {
+ LOG.trace("Nothing on the async queue");
+ }
+ }
+ }
+
+ private boolean checkForParseException(FetchEmitTuple request, EmitData emitData) {
+ if (emitData == null || emitData.getMetadataList() == null ||
+ emitData.getMetadataList().size() == 0) {
+ LOG.warn("empty or null emit data ({})", request.getFetchKey().getKey());
+ return false;
+ }
+ boolean shouldEmit = true;
+ Metadata container = emitData.getMetadataList().get(0);
+ String stack = container.get(TikaCoreProperties.CONTAINER_EXCEPTION);
+ if (stack != null) {
+ LOG.warn("fetchKey ({}) container parse exception ({})",
+ request.getFetchKey().getKey(), stack);
+ if (request.getOnParseException() == FetchEmitTuple.ON_PARSE_EXCEPTION.SKIP) {
+ shouldEmit = false;
+ }
+ }
+
+ for (int i = 1; i < emitData.getMetadataList().size(); i++) {
+ Metadata m = emitData.getMetadataList().get(i);
+ String embeddedStack = m.get(TikaCoreProperties.EMBEDDED_EXCEPTION);
+ if (embeddedStack != null) {
+ LOG.warn("fetchKey ({}) embedded parse exception ({})",
+ request.getFetchKey().getKey(), embeddedStack);
+ }
+ }
+ return shouldEmit;
+ }
+
+ private EmitData processTuple(FetchEmitTuple t) {
+ Metadata userMetadata = t.getMetadata();
+ Metadata metadata = new Metadata();
+ String fetcherName = t.getFetchKey().getFetcherName();
+ String fetchKey = t.getFetchKey().getKey();
+ List<Metadata> metadataList = null;
+ try (InputStream stream =
+ TikaResource.getConfig().getFetcherManager()
+ .getFetcher(fetcherName).fetch(fetchKey, metadata)) {
+ metadataList = RecursiveMetadataResource.parseMetadata(
+ stream,
+ metadata,
+ new MultivaluedHashMap<>(),
+ new UriInfoImpl(new MessageImpl()), "text");
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Exception e) {
+ LOG.warn(t.toString(), e);
+ }
+
+ injectUserMetadata(userMetadata, metadataList);
+ EmitKey emitKey = t.getEmitKey();
+ if (StringUtils.isBlank(emitKey.getKey())) {
+ emitKey = new EmitKey(emitKey.getEmitterName(), fetchKey);
+ }
+ return new EmitData(emitKey, metadataList);
+ }
+
+ private void injectUserMetadata(Metadata userMetadata, List<Metadata> metadataList) {
+ for (String n : userMetadata.names()) {
+ //overwrite whatever was there
+ metadataList.get(0).set(n, null);
+ for (String val : userMetadata.getValues(n)) {
+ metadataList.get(0).add(n, val);
+ }
+ }
+ }
+}
diff --git a/tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncRequest.java
similarity index 69%
copy from tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java
copy to tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncRequest.java
index 1117537..9e3566c 100644
--- a/tika-core/src/main/java/org/apache/tika/pipes/emitter/AbstractEmitter.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncRequest.java
@@ -14,21 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.tika.pipes.emitter;
+package org.apache.tika.server.core.resource;
-import org.apache.tika.config.Field;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
-public abstract class AbstractEmitter implements Emitter {
+import java.util.List;
- private String name;
+public class AsyncRequest {
+ private final List<FetchEmitTuple> tuples;
- @Field
- public void setName(String name) {
- this.name = name;
+ public AsyncRequest(List<FetchEmitTuple> tuples) {
+ this.tuples = tuples;
}
- @Override
- public String getName() {
- return name;
+ public List<FetchEmitTuple> getTuples() {
+ return tuples;
}
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncResource.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncResource.java
new file mode 100644
index 0000000..248ebb0
--- /dev/null
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/AsyncResource.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tika.server.core.resource;
+
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTupleList;
+import org.apache.tika.pipes.emitter.EmitData;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.emitter.EmitterManager;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetcher.FetcherManager;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.BadRequestException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@Path("/async")
+public class AsyncResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AsyncResource.class);
+
+ private static final int DEFAULT_FETCH_EMIT_QUEUE_SIZE = 10000;
+ long maxQueuePauseMs = 60000;
+ private ArrayBlockingQueue<FetchEmitTuple> queue;
+
+ public ArrayBlockingQueue<FetchEmitTuple> getFetchEmitQueue(int queueSize) {
+ this.queue = new ArrayBlockingQueue<>(queueSize);
+ return queue;
+ }
+
+ public ArrayBlockingQueue<EmitData> getEmitDataQueue(int size) {
+ return new ArrayBlockingQueue<>(size);
+ }
+ /**
+ * The client posts a json request. At a minimum, this must be a
+ * json object that contains an emitter and a fetcherString key with
+ * the key to fetch the inputStream. Optionally, it may contain a metadata
+ * object that will be used to populate the metadata key for pass
+ * through of metadata from the client.
+ * <p>
+ * The extracted text content is stored with the key
+ * {@link TikaCoreProperties#TIKA_CONTENT}
+ * <p>
+ * Must specify a fetcherString and an emitter in the posted json.
+ *
+ * @param info uri info
+ * @return InputStream that can be deserialized as a list of {@link Metadata} objects
+ * @throws Exception
+ */
+ @POST
+ @Produces("application/json")
+ public Map<String, Object> post(InputStream is,
+ @Context HttpHeaders httpHeaders,
+ @Context UriInfo info
+ ) throws Exception {
+
+ AsyncRequest request = deserializeASyncRequest(is);
+
+ //make sure that there are no problems with
+ //the requested fetchers and emitters
+ //throw early
+ FetcherManager fetcherManager = TikaResource.getConfig().getFetcherManager();
+ EmitterManager emitterManager = TikaResource.getConfig().getEmitterManager();
+ for (FetchEmitTuple t : request.getTuples()) {
+ if (! fetcherManager.getSupported().contains(t.getFetchKey().getFetcherName())) {
+ return badFetcher(t.getFetchKey());
+ }
+ if (! emitterManager.getSupported().contains(t.getEmitKey().getEmitterName())) {
+ return badEmitter(t.getEmitKey());
+ }
+ }
+ Instant start = Instant.now();
+ long elapsed = ChronoUnit.MILLIS.between(start, Instant.now());
+ List<FetchEmitTuple> notAdded = new ArrayList<>();
+ int addedCount = 0;
+ for (FetchEmitTuple t : request.getTuples()) {
+ boolean offered = false;
+ while (!offered && elapsed < maxQueuePauseMs) {
+ offered = queue.offer(t, 10, TimeUnit.MILLISECONDS);
+ elapsed = ChronoUnit.MILLIS.between(start, Instant.now());
+ }
+ if (! offered) {
+ notAdded.add(t);
+ } else {
+ addedCount++;
+ }
+ }
+
+ if (notAdded.size() > 0) {
+ return throttle(notAdded, addedCount);
+ }
+ return ok(request.getTuples().size());
+ }
+
+ private Map<String, Object> ok(int size) {
+ Map<String, Object> map = new HashMap<>();
+ map.put("status", "ok");
+ map.put("added", size);
+ return map;
+ }
+
+ private Map<String, Object> throttle(List<FetchEmitTuple> notAdded, int added) {
+ List<String> fetchKeys = new ArrayList<>();
+ for (FetchEmitTuple t : notAdded) {
+ fetchKeys.add(t.getFetchKey().getKey());
+ }
+ Map<String, Object> map = new HashMap<>();
+ map.put("status", "throttled");
+ map.put("added", added);
+ map.put("skipped", notAdded.size());
+ map.put("skippedFetchKeys", fetchKeys);
+ return map;
+ }
+
+ private Map<String, Object> badEmitter(EmitKey emitKey) {
+ throw new BadRequestException("can't find emitter for "+emitKey.getEmitterName());
+ }
+
+ private Map<String, Object> badFetcher(FetchKey fetchKey) {
+ throw new BadRequestException("can't find fetcher for " + fetchKey.getFetcherName());
+ }
+
+ private AsyncRequest deserializeASyncRequest(InputStream is) throws IOException {
+ try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
+ return new AsyncRequest(JsonFetchEmitTupleList.fromJson(reader));
+ }
+ }
+
+}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/EmitterResource.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/EmitterResource.java
index 9689ba8..6338dc4 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/EmitterResource.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/EmitterResource.java
@@ -17,15 +17,19 @@
package org.apache.tika.server.core.resource;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import org.apache.tika.Tika;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTuple;
+import org.apache.tika.pipes.emitter.EmitKey;
import org.apache.tika.pipes.emitter.Emitter;
import org.apache.tika.pipes.emitter.TikaEmitterException;
import org.apache.tika.exception.TikaException;
+import org.apache.tika.pipes.fetcher.FetchKey;
import org.apache.tika.pipes.fetcher.Fetcher;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
import org.apache.tika.utils.ExceptionUtils;
import org.apache.tika.utils.StringUtils;
import org.slf4j.Logger;
@@ -46,6 +50,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -95,7 +100,7 @@ public class EmitterResource {
httpHeaders.getRequestHeaders(), info, "text");
}
emitKey = StringUtils.isBlank(emitKey) ? fetchKey : emitKey;
- return emit(emitterName, emitKey, metadataList);
+ return emit(new EmitKey(emitterName, emitKey), metadataList);
}
/**
@@ -129,7 +134,7 @@ public class EmitterResource {
RecursiveMetadataResource.parseMetadata(is,
metadata,
httpHeaders.getRequestHeaders(), info, "text");
- return emit(emitterName, emitKey, metadataList);
+ return emit(new EmitKey(emitterName, emitKey), metadataList);
}
/**
@@ -154,52 +159,92 @@ public class EmitterResource {
@Context HttpHeaders httpHeaders,
@Context UriInfo info
) throws Exception {
- JsonObject root = null;
+ FetchEmitTuple t = null;
try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
- root = JsonParser.parseReader(reader).getAsJsonObject();
+ t = JsonFetchEmitTuple.fromJson(reader);
}
- String fetcherName = root.get("fetcher").getAsString();
- String fetchKey = root.get("fetchKey").getAsString();
- String emitKey = (root.has("emitKey")) ?
- root.get("emitKey").getAsString() : fetchKey;
- String emitterName = root.get("emitter").getAsString();
Metadata metadata = new Metadata();
-
List<Metadata> metadataList = null;
try (InputStream stream =
TikaResource.getConfig().getFetcherManager()
- .getFetcher(fetcherName).fetch(fetchKey, metadata)) {
+ .getFetcher(t.getFetchKey().getFetcherName())
+ .fetch(t.getFetchKey().getKey(), metadata)) {
metadataList = RecursiveMetadataResource.parseMetadata(
stream,
metadata,
httpHeaders.getRequestHeaders(), info, "text");
} catch (Error error) {
- return returnError(emitterName, error);
+ return returnError(t.getEmitKey().getEmitterName(), error);
+ }
+
+ boolean shouldEmit = checkParseException(t, metadataList);
+ if (! shouldEmit) {
+ return skip(t, metadataList);
}
- injectUserMetadata(metadataList.get(0), root.getAsJsonObject());
+ injectUserMetadata(t.getMetadata(), metadataList.get(0));
for (String n : metadataList.get(0).names()) {
LOG.debug("post parse/pre emit metadata {}: {}",
n, metadataList.get(0).get(n));
}
- return emit(emitterName, emitKey, metadataList);
+ return emit(calcEmitKey(t), metadataList);
+ }
+
+ static EmitKey calcEmitKey(FetchEmitTuple t) {
+ //use fetch key if emitter key is not specified
+ //TODO: clean this up?
+ EmitKey emitKey = t.getEmitKey();
+ if (StringUtils.isBlank(emitKey.getKey())) {
+ emitKey = new EmitKey(emitKey.getEmitterName(), t.getFetchKey().getKey());
+ }
+ return emitKey;
+ }
+
+ private Map<String, String> skip(FetchEmitTuple t, List<Metadata> metadataList) {
+ Map<String, String> statusMap = new HashMap<>();
+ statusMap.put("status", "ok");
+ statusMap.put("emitter", t.getEmitKey().getEmitterName());
+ statusMap.put("emitKey", t.getEmitKey().getKey());
+ String msg = metadataList.get(0).get(TikaCoreProperties.CONTAINER_EXCEPTION);
+ statusMap.put("parse_exception", msg);
+ return statusMap;
}
- private void injectUserMetadata(Metadata metadata, JsonObject root) {
- if (root.has("metadata")) {
- JsonObject meta = root.getAsJsonObject("metadata");
- for (String k : meta.keySet()) {
- JsonElement val = meta.get(k);
- if (val.isJsonArray()) {
- for (JsonElement v : val.getAsJsonArray()) {
- metadata.add(k, v.getAsString());
- }
- } else {
- metadata.set(k, val.getAsString());
- }
+ private boolean checkParseException(FetchEmitTuple t, List<Metadata> metadataList) {
+ if (metadataList == null || metadataList.size() < 1) {
+ return false;
+ }
+ boolean shouldEmit = true;
+ String stack = metadataList.get(0).get(TikaCoreProperties.CONTAINER_EXCEPTION);
+ if (stack != null) {
+ if (t.getOnParseException() == FetchEmitTuple.ON_PARSE_EXCEPTION.SKIP) {
+ shouldEmit = false;
+ }
+ LOG.warn("fetchKey ({}) container parse exception ({})",
+ t.getFetchKey().getKey(), stack);
+ }
+
+ for (int i = 1; i < metadataList.size(); i++) {
+ Metadata m = metadataList.get(i);
+ String embeddedStack = m.get(TikaCoreProperties.EMBEDDED_EXCEPTION);
+ if (embeddedStack != null) {
+ LOG.warn("fetchKey ({}) embedded parse exception ({})",
+ t.getFetchKey().getKey(), embeddedStack);
+ }
+ }
+
+ return shouldEmit;
+ }
+
+
+ private void injectUserMetadata(Metadata userMetadata, Metadata metadata) {
+ for (String n : userMetadata.names()) {
+ metadata.set(n, null);
+ for (String v : userMetadata.getValues(n)) {
+ metadata.add(n, v);
}
}
}
@@ -213,20 +258,20 @@ public class EmitterResource {
return statusMap;
}
- private Map<String, String> emit(String emitterName, String emitKey, List<Metadata> metadataList) throws TikaException {
- Emitter emitter = TikaResource.getConfig().getEmitterManager().getEmitter(emitterName);
+ private Map<String, String> emit(EmitKey emitKey, List<Metadata> metadataList) throws TikaException {
+ Emitter emitter = TikaResource.getConfig().getEmitterManager().getEmitter(emitKey.getEmitterName());
String status = "ok";
String exceptionMsg = "";
try {
- emitter.emit(emitKey, metadataList);
+ emitter.emit(emitKey.getKey(), metadataList);
} catch (IOException | TikaEmitterException e) {
- LOG.warn("problem with emitting", e);
+ LOG.warn("problem emitting ("+emitKey.getKey()+")", e);
status = "emitter_exception";
exceptionMsg = ExceptionUtils.getStackTrace(e);
}
Map<String, String> statusMap = new HashMap<>();
statusMap.put("status", status);
- statusMap.put("emitter", emitterName);
+ statusMap.put("emitter", emitKey.getEmitterName());
if (exceptionMsg.length() > 0) {
statusMap.put("emitter_exception", exceptionMsg);
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
index 8668b16..7a634fd 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
@@ -132,7 +132,7 @@ public class MetadataResource {
//no need to parse embedded docs
context.set(DocumentSelector.class, metadata1 -> false);
- TikaResource.logRequest(LOG, info, metadata);
+ TikaResource.logRequest(LOG, "/meta", metadata);
TikaResource.parse(parser, LOG, info.getPath(), is,
new LanguageHandler() {
public void endDocument() {
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
index 298d848..f6f340c 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
@@ -23,6 +23,7 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
@@ -39,6 +40,7 @@ import org.apache.tika.parser.RecursiveParserWrapper;
import org.apache.tika.sax.BasicContentHandlerFactory;
import org.apache.tika.sax.RecursiveParserWrapperHandler;
import org.apache.tika.server.core.MetadataList;
+import org.apache.tika.server.core.TikaServerParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -62,7 +64,7 @@ public class RecursiveMetadataResource {
* just the immediate children.
* <p>
* The extracted text content is stored with the key
- * {@link RecursiveParserWrapper#TIKA_CONTENT}.
+ * {@link org.apache.tika.metadata.TikaCoreProperties#TIKA_CONTENT}.
* <p>
* Specify the handler for the content (xml, html, text, ignore)
* in the path:<br/>
@@ -98,7 +100,7 @@ public class RecursiveMetadataResource {
* just the immediate children.
* <p>
* The extracted text content is stored with the key
- * {@link RecursiveParserWrapper#TIKA_CONTENT}.
+ * {@link org.apache.tika.metadata.TikaCoreProperties#TIKA_CONTENT}.
* <p>
* Specify the handler for the content (xml, html, text, ignore)
* in the path:<br/>
@@ -134,15 +136,15 @@ public class RecursiveMetadataResource {
UriInfo info, String handlerTypeName)
throws Exception {
- final ParseContext context = new ParseContext();
- Parser parser = TikaResource.createParser();
- // TODO: parameterize choice of max chars/max embedded attachments
- RecursiveParserWrapper wrapper = new RecursiveParserWrapper(parser);
+ final ParseContext context = new ParseContext();
+ Parser parser = TikaResource.createParser();
+ // TODO: parameterize choice of max chars/max embedded attachments
+ RecursiveParserWrapper wrapper = new RecursiveParserWrapper(parser);
fillMetadata(parser, metadata, httpHeaders);
fillParseContext(httpHeaders, metadata, context);
- TikaResource.logRequest(LOG, info, metadata);
+ TikaResource.logRequest(LOG, "/rmeta", metadata);
int writeLimit = -1;
if (httpHeaders.containsKey("writeLimit")) {
@@ -156,24 +158,20 @@ public class RecursiveMetadataResource {
BasicContentHandlerFactory.HANDLER_TYPE type =
BasicContentHandlerFactory.parseHandlerType(handlerTypeName, DEFAULT_HANDLER_TYPE);
- RecursiveParserWrapperHandler handler = new RecursiveParserWrapperHandler(
- new BasicContentHandlerFactory(type, writeLimit), maxEmbeddedResources,
+ RecursiveParserWrapperHandler handler = new RecursiveParserWrapperHandler(
+ new BasicContentHandlerFactory(type, writeLimit), maxEmbeddedResources,
TikaResource.getConfig().getMetadataFilter());
- try {
- TikaResource.parse(wrapper, LOG, info.getPath(), is, handler, metadata, context);
- } catch (SecurityException e) {
+ try {
+ TikaResource.parse(wrapper, LOG, "/rmeta", is, handler, metadata, context);
+ } catch (TikaServerParseException e) {
+ //do nothing
+ } catch (SecurityException|WebApplicationException e) {
throw e;
} catch (Exception e) {
- //swallow it and report it via the metadata list
+ //we shouldn't get here?
+ e.printStackTrace();
}
- /*
- We used to have this non-functional bit of code...refactor to add it back and make it work?
- new LanguageHandler() {
- public void endDocument() {
- metadata.set("language", getLanguage().getLanguage());
- }
- },
- */
+
return handler.getMetadataList();
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaDetectors.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaDetectors.java
index ce163d5..5b738fb 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaDetectors.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaDetectors.java
@@ -19,13 +19,13 @@ package org.apache.tika.server.core.resource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.tika.detect.CompositeDetector;
import org.apache.tika.detect.Detector;
import org.apache.tika.server.core.HTMLHelper;
@@ -36,8 +36,6 @@ import org.apache.tika.server.core.HTMLHelper;
*/
@Path("/detectors")
public class TikaDetectors {
- private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
-
private HTMLHelper html;
@@ -77,10 +75,10 @@ public class TikaDetectors {
@GET
@Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
- public String getDetectorsJSON() {
+ public String getDetectorsJSON() throws IOException {
Map<String, Object> details = new HashMap<String, Object>();
detectorAsMap(TikaResource.getConfig().getDetector(), details);
- return GSON.toJson(details);
+ return new ObjectMapper().writeValueAsString(details);
}
private void detectorAsMap(Detector d, Map<String, Object> details) {
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaMimeTypes.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaMimeTypes.java
index be1d84b..c45fb25 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaMimeTypes.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaMimeTypes.java
@@ -19,6 +19,7 @@ package org.apache.tika.server.core.resource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -26,8 +27,7 @@ import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.tika.mime.MediaType;
import org.apache.tika.mime.MediaTypeRegistry;
import org.apache.tika.parser.CompositeParser;
@@ -41,8 +41,6 @@ import org.apache.tika.server.core.HTMLHelper;
@Path("/mime-types")
public class TikaMimeTypes {
- private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
-
private HTMLHelper html;
public TikaMimeTypes() {
@@ -94,7 +92,7 @@ public class TikaMimeTypes {
@GET
@Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
- public String getMimeTypesJSON() {
+ public String getMimeTypesJSON() throws IOException {
Map<String, Object> details = new HashMap<String, Object>();
for (MediaTypeDetails type : getMediaTypes()) {
@@ -111,7 +109,8 @@ public class TikaMimeTypes {
details.put(type.type.toString(), typeDets);
}
- return GSON.toJson(details);
+ return new ObjectMapper().writerWithDefaultPrettyPrinter()
+ .writeValueAsString(details);
}
private static String[] copyToStringArray(MediaType[] aliases) {
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaParsers.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaParsers.java
index f1c4abb..400230c 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaParsers.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaParsers.java
@@ -19,6 +19,7 @@ package org.apache.tika.server.core.resource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -28,8 +29,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.CompositeParser;
import org.apache.tika.parser.ParseContext;
@@ -45,7 +45,6 @@ import org.apache.tika.server.core.HTMLHelper;
@Path("/parsers")
public class TikaParsers {
private static final ParseContext EMPTY_PC = new ParseContext();
- private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
private HTMLHelper html;
public TikaParsers() {
@@ -116,21 +115,23 @@ public class TikaParsers {
@GET
@Path("/details")
@Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
- public String getParserDetailsJSON() {
+ public String getParserDetailsJSON() throws IOException {
return getParsersJSON(true);
}
@GET
@Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
- public String getParsersJSON() {
+ public String getParsersJSON() throws IOException {
return getParsersJSON(false);
}
- protected String getParsersJSON(boolean withMimeTypes) {
+ protected String getParsersJSON(boolean withMimeTypes) throws IOException {
Map<String, Object> details = new HashMap<String, Object>();
parserAsMap(new ParserDetails(TikaResource.getConfig().getParser()), withMimeTypes, details);
-
- return GSON.toJson(details);
+ ObjectMapper objectMapper = new ObjectMapper();
+ return objectMapper
+ .writerWithDefaultPrettyPrinter()
+ .writeValueAsString(details);
}
private void parserAsMap(ParserDetails p, boolean withMimeTypes, Map<String, Object> details) {
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
index 46cf093..d2c33e9 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
@@ -354,11 +354,12 @@ public class TikaResource {
}
}
- public static void logRequest(Logger logger, UriInfo info, Metadata metadata) {
+ public static void logRequest(Logger logger, String endpoint, Metadata metadata) {
+
if (metadata.get(org.apache.tika.metadata.HttpHeaders.CONTENT_TYPE) == null) {
- logger.info("{} (autodetecting type)", info.getPath());
+ logger.info("{} (autodetecting type)", endpoint);
} else {
- logger.info("{} ({})", info.getPath(), metadata.get(org.apache.tika.metadata.HttpHeaders.CONTENT_TYPE));
+ logger.info("{} ({})", endpoint, metadata.get(org.apache.tika.metadata.HttpHeaders.CONTENT_TYPE));
}
}
@@ -403,7 +404,7 @@ public class TikaResource {
fillMetadata(parser, metadata, httpHeaders);
fillParseContext(httpHeaders, metadata, context);
- logRequest(LOG, info, metadata);
+ logRequest(LOG, "/tika", metadata);
return new StreamingOutput() {
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
@@ -432,7 +433,7 @@ public class TikaResource {
fillMetadata(parser, metadata, httpHeaders);
fillParseContext(httpHeaders, metadata, context);
- logRequest(LOG, info, metadata);
+ logRequest(LOG, "/tika", metadata);
return new StreamingOutput() {
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
@@ -489,7 +490,7 @@ public class TikaResource {
fillParseContext(httpHeaders, metadata, context);
- logRequest(LOG, info, metadata);
+ logRequest(LOG, "/tika", metadata);
return new StreamingOutput() {
public void write(OutputStream outputStream)
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
index ed0320b..a3d733a 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
@@ -126,7 +126,7 @@ public class UnpackerResource {
fillMetadata(parser, metadata, httpHeaders.getRequestHeaders());
fillParseContext(httpHeaders.getRequestHeaders(), metadata, pc);
- TikaResource.logRequest(LOG, info, metadata);
+ TikaResource.logRequest(LOG, "/unpack", metadata);
//even though we aren't currently parsing embedded documents,
//we need to add this to allow for "inline" use of other parsers.
pc.set(Parser.class, parser);
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONMessageBodyWriter.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONMessageBodyWriter.java
index d3ff0a8..a0438af 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONMessageBodyWriter.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONMessageBodyWriter.java
@@ -53,13 +53,9 @@ public class JSONMessageBodyWriter implements MessageBodyWriter<Metadata> {
public void writeTo(Metadata metadata, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException,
WebApplicationException {
- try {
- Writer writer = new OutputStreamWriter(entityStream, UTF_8);
- JsonMetadata.toJson(metadata, writer);
- writer.flush();
- } catch (TikaException e) {
- throw new IOException(e);
- }
+ Writer writer = new OutputStreamWriter(entityStream, UTF_8);
+ JsonMetadata.toJson(metadata, writer);
+ writer.flush();
entityStream.flush();
}
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONObjWriter.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONObjWriter.java
index f71fde3..c79ac48 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONObjWriter.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/JSONObjWriter.java
@@ -17,8 +17,7 @@
package org.apache.tika.server.core.writer;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.tika.metadata.Metadata;
import javax.ws.rs.Produces;
@@ -40,7 +39,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JSONObjWriter implements MessageBodyWriter<Map<String, Object>> {
- private static Gson GSON = new GsonBuilder().setPrettyPrinting().create();
+
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Map.class.isAssignableFrom(type);
@@ -55,8 +54,8 @@ public class JSONObjWriter implements MessageBodyWriter<Map<String, Object>> {
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
Writer writer = new OutputStreamWriter(entityStream, UTF_8);
- GSON.toJson(map, writer);
- writer.flush();
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.writerWithDefaultPrettyPrinter().writeValue(writer, map);
entityStream.flush();
}
}
diff --git a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/MetadataListMessageBodyWriter.java b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/MetadataListMessageBodyWriter.java
index cedfcba..647da2d 100644
--- a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/MetadataListMessageBodyWriter.java
+++ b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/writer/MetadataListMessageBodyWriter.java
@@ -56,13 +56,9 @@ public class MetadataListMessageBodyWriter implements MessageBodyWriter<Metadata
public void writeTo(MetadataList list, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException,
WebApplicationException {
- try {
- Writer writer = new OutputStreamWriter(entityStream, UTF_8);
- JsonMetadataList.toJson(list.getMetadata(), writer);
- writer.flush();
- } catch (TikaException e) {
- throw new IOException(e);
- }
+ Writer writer = new OutputStreamWriter(entityStream, UTF_8);
+ JsonMetadataList.toJson(list.getMetadata(), writer);
+ writer.flush();
entityStream.flush();
}
}
diff --git a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaEmitterTest.java b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaEmitterTest.java
index 31a3cd0..3c92674 100644
--- a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaEmitterTest.java
+++ b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaEmitterTest.java
@@ -16,11 +16,8 @@
*/
package org.apache.tika.server.core;
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonPrimitive;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
@@ -29,7 +26,11 @@ import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTuple;
import org.apache.tika.metadata.serialization.JsonMetadataList;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
import org.apache.tika.server.core.resource.EmitterResource;
import org.apache.tika.server.core.writer.JSONObjWriter;
import org.junit.AfterClass;
@@ -42,6 +43,7 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -68,6 +70,11 @@ public class TikaEmitterTest extends CXFTestBase {
private static String HELLO_WORLD = "hello_world.xml";
private static String HELLO_WORLD_JSON = "hello_world.xml.json";
+ private static String[] VALUE_ARRAY = new String[]{
+ "my-value-1",
+ "my-value-2",
+ "my-value-3"
+ };
@BeforeClass
public static void setUpBeforeClass() throws Exception {
TMP_DIR = Files.createTempDirectory("tika-emitter-test-");
@@ -128,6 +135,7 @@ public class TikaEmitterTest extends CXFTestBase {
@Override
protected void setUpProviders(JAXRSServerFactoryBean sf) {
List<Object> providers = new ArrayList<>();
+ providers.add(new TikaServerParseExceptionMapper(true));
providers.add(new JSONObjWriter());
sf.setProviders(providers);
}
@@ -167,27 +175,24 @@ public class TikaEmitterTest extends CXFTestBase {
@Test
public void testPost() throws Exception {
- JsonObject root = new JsonObject();
- root.add("fetcher", new JsonPrimitive("fsf"));
- root.add("fetchKey", new JsonPrimitive("hello_world.xml"));
- root.add("emitter", new JsonPrimitive("fse"));
- JsonObject userMetadata = new JsonObject();
- String[] valueArray = new String[] {"my-value-1", "my-value-2", "my-value-3"};
- JsonArray arr = new JsonArray();
- for (int i = 0; i < valueArray.length; i++) {
- arr.add(valueArray[i]);
+ Metadata userMetadata = new Metadata();
+ userMetadata.set("my-key", "my-value");
+ for (int i = 0; i < VALUE_ARRAY.length; i++) {
+ userMetadata.add("my-key-multi", VALUE_ARRAY[i]);
}
- userMetadata.add("my-key", new JsonPrimitive("my-value"));
- userMetadata.add("my-key-multi", arr);
- root.add("metadata", userMetadata);
- String jsonPost = new Gson().toJson(root);
+ FetchEmitTuple t = new FetchEmitTuple(
+ new FetchKey("fsf", "hello_world.xml"),
+ new EmitKey("fse", ""),
+ userMetadata);
+ StringWriter writer = new StringWriter();
+ JsonFetchEmitTuple.toJson(t, writer);
String getUrl = endPoint+EMITTER_PATH;
Response response = WebClient
.create(getUrl)
.accept("application/json")
- .post(jsonPost);
+ .post(writer.toString());
assertEquals(200, response.getStatus());
List<Metadata> metadataList = null;
@@ -202,7 +207,7 @@ public class TikaEmitterTest extends CXFTestBase {
assertEquals("你好,世界", metadata.get("title"));
assertEquals("application/mock+xml", metadata.get(Metadata.CONTENT_TYPE));
assertEquals("my-value", metadata.get("my-key"));
- assertArrayEquals(valueArray, metadata.getValues("my-key-multi"));
+ assertArrayEquals(VALUE_ARRAY, metadata.getValues("my-key-multi"));
}
@Test
@@ -235,36 +240,32 @@ public class TikaEmitterTest extends CXFTestBase {
@Test
public void testPostNPE() throws Exception {
-
- JsonObject root = new JsonObject();
- root.add("fetcher", new JsonPrimitive("fsf"));
- root.add("fetchKey", new JsonPrimitive("null_pointer.xml"));
- root.add("emitter", new JsonPrimitive("fse"));
- JsonObject userMetadata = new JsonObject();
- String[] valueArray = new String[] {"my-value-1", "my-value-2", "my-value-3"};
- JsonArray arr = new JsonArray();
- for (int i = 0; i < valueArray.length; i++) {
- arr.add(valueArray[i]);
+ Metadata userMetadata = new Metadata();
+ userMetadata.set("my-key", "my-value");
+ for (int i = 0; i < VALUE_ARRAY.length; i++) {
+ userMetadata.add("my-key-multi", VALUE_ARRAY[i]);
}
- userMetadata.add("my-key", new JsonPrimitive("my-value"));
- userMetadata.add("my-key-multi", arr);
- root.add("metadata", userMetadata);
- String jsonPost = new Gson().toJson(root);
+ FetchEmitTuple t = new FetchEmitTuple(
+ new FetchKey("fsf", "null_pointer.xml"),
+ new EmitKey("fse", ""),
+ userMetadata);
+ StringWriter writer = new StringWriter();
+ JsonFetchEmitTuple.toJson(t, writer);
String getUrl = endPoint+EMITTER_PATH;
Response response = WebClient
.create(getUrl)
.accept("application/json")
- .post(jsonPost);
+ .post(writer.toString());
assertEquals(200, response.getStatus());
- JsonObject jsonResponse;
+ JsonNode jsonResponse;
try (Reader reader = new InputStreamReader(
(InputStream)response.getEntity(), StandardCharsets.UTF_8)) {
- jsonResponse = JsonParser.parseReader(reader).getAsJsonObject();
+ jsonResponse = new ObjectMapper().readTree(reader);
};
- String parseException = jsonResponse.get("parse_exception").getAsString();
+ String parseException = jsonResponse.get("parse_exception").asText();
assertNotNull(parseException);
assertContains("NullPointerException", parseException);
@@ -276,7 +277,7 @@ public class TikaEmitterTest extends CXFTestBase {
Metadata metadata = metadataList.get(0);
assertEquals("application/mock+xml", metadata.get(Metadata.CONTENT_TYPE));
assertEquals("my-value", metadata.get("my-key"));
- assertArrayEquals(valueArray, metadata.getValues("my-key-multi"));
+ assertArrayEquals(VALUE_ARRAY, metadata.getValues("my-key-multi"));
assertContains("NullPointerException", metadata.get(TikaCoreProperties.CONTAINER_EXCEPTION));
}
diff --git a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaMimeTypesTest.java b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaMimeTypesTest.java
index 567e681..2f76124 100644
--- a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaMimeTypesTest.java
+++ b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaMimeTypesTest.java
@@ -26,8 +26,6 @@ import java.io.InputStream;
import java.util.List;
import java.util.Map;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
@@ -37,7 +35,6 @@ import org.junit.Test;
public class TikaMimeTypesTest extends CXFTestBase {
- private static final Gson GSON = new GsonBuilder().create();
private static final String MIMETYPES_PATH = "/mime-types";
diff --git a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerAsyncIntegrationTest.java
similarity index 57%
copy from tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java
copy to tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerAsyncIntegrationTest.java
index 554aee1..e1812dc 100644
--- a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java
+++ b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerAsyncIntegrationTest.java
@@ -16,56 +16,61 @@
*/
package org.apache.tika.server.core;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonPrimitive;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTupleList;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Response;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.List;
-import java.util.Random;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
+@Ignore("useful for development...need to turn it into a real unit test")
+public class TikaServerAsyncIntegrationTest extends IntegrationTestBase {
- private static final Logger LOG = LoggerFactory.getLogger(TikaServerEmitterIntegrationTest.class);
+ private static final Logger LOG = LoggerFactory.getLogger(TikaServerAsyncIntegrationTest.class);
+ private static FetchEmitTuple.ON_PARSE_EXCEPTION ON_PARSE_EXCEPTION
+ = FetchEmitTuple.ON_PARSE_EXCEPTION.EMIT;
private static Path TMP_DIR;
private static Path TMP_OUTPUT_DIR;
private static String TIKA_CONFIG_XML;
private static Path TIKA_CONFIG;
- private static Gson GSON = new GsonBuilder().create();
+ private static final int NUM_FILES = 1000;
private static final String EMITTER_NAME = "fse";
private static final String FETCHER_NAME = "fsf";
+ private static List<String> FILE_LIST = new ArrayList<>();
private static String[] FILES = new String[] {
- "hello_world.xml",
- "heavy_hang_30000.xml", "real_oom.xml", "system_exit.xml"
+ "hello_world.xml", "null_pointer.xml"
+ // "heavy_hang_30000.xml", "real_oom.xml", "system_exit.xml"
};
@BeforeClass
@@ -76,10 +81,16 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
Files.createDirectories(inputDir);
Files.createDirectories(TMP_OUTPUT_DIR);
- for (String mockFile : FILES) {
- Files.copy(TikaEmitterTest.class.getResourceAsStream(
- "/test-documents/mock/"+mockFile),
- inputDir.resolve(mockFile));
+ for (int i = 0; i < NUM_FILES; i++) {
+ for (String mockFile : FILES) {
+ String targetName = i+"-"+mockFile;
+ Path target = inputDir.resolve(targetName);
+ FILE_LIST.add(targetName);
+ Files.copy(TikaEmitterTest.class.getResourceAsStream(
+ "/test-documents/mock/" + mockFile),
+ target);
+
+ }
}
TIKA_CONFIG = TMP_DIR.resolve("tika-config.xml");
@@ -134,7 +145,7 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
TikaServerCli.main(
new String[]{
"-enableUnsecureFeatures",
- "-maxFiles", "2000",
+ "-maxFiles", "10000",
"-p", INTEGRATION_TEST_PORT,
"-tmpFilePrefix", "basic-",
"-config", TIKA_CONFIG.toAbsolutePath().toString()
@@ -142,89 +153,29 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
}
};
serverThread.start();
- try {
- testOne("hello_world.xml", true);
- } finally {
- serverThread.interrupt();
- }
- }
- @Test(expected = ProcessingException.class)
- public void testSystemExit() throws Exception {
-
- Thread serverThread = new Thread() {
- @Override
- public void run() {
- TikaServerCli.main(
- new String[]{
- "-enableUnsecureFeatures",
- "-maxFiles", "2000",
- "-p", INTEGRATION_TEST_PORT,
- "-tmpFilePrefix", "basic-",
- "-config", TIKA_CONFIG.toAbsolutePath().toString()
- });
- }
- };
- serverThread.start();
try {
- testOne("system_exit.xml", false);
- } finally {
- serverThread.interrupt();
- }
- }
-
- @Test
- public void testOOM() throws Exception {
-
- Thread serverThread = new Thread() {
- @Override
- public void run() {
- TikaServerCli.main(
- new String[]{
- "-enableUnsecureFeatures",
- "-JXmx128m",
- "-maxFiles", "2000",
- "-p", INTEGRATION_TEST_PORT,
- "-tmpFilePrefix", "basic-",
- "-config", TIKA_CONFIG.toAbsolutePath().toString()
- });
+ JsonNode response = sendAsync(FILE_LIST);
+ System.out.println(response);
+ int expected = (ON_PARSE_EXCEPTION == FetchEmitTuple.ON_PARSE_EXCEPTION.EMIT) ?
+ FILE_LIST.size() : FILE_LIST.size()/2;
+ int targets = 0;
+ while (targets < FILE_LIST.size()) {
+ System.out.println("targets "+targets);
+ targets = countTargets();
+ Thread.sleep(1000);
}
- };
- serverThread.start();
- try {
- JsonObject response = testOne("real_oom.xml", false);
- assertContains("heap space", response.get("parse_error").getAsString());
+ System.out.println("TARGETS: "+targets);
} finally {
serverThread.interrupt();
}
}
- @Test(expected = ProcessingException.class)
- public void testTimeout() throws Exception {
-
- Thread serverThread = new Thread() {
- @Override
- public void run() {
- TikaServerCli.main(
- new String[]{
- "-enableUnsecureFeatures",
- "-JXmx128m",
- "-taskTimeoutMillis", "2000", "-taskPulseMillis", "100",
- "-p", INTEGRATION_TEST_PORT,
- "-tmpFilePrefix", "basic-",
- "-config", TIKA_CONFIG.toAbsolutePath().toString()
- });
- }
- };
- serverThread.start();
- try {
- JsonObject response = testOne("heavy_hang_30000.xml", false);
- assertContains("heap space", response.get("parse_error").getAsString());
- } finally {
- serverThread.interrupt();
- }
+ private int countTargets() {
+ return TMP_OUTPUT_DIR.toFile().listFiles().length;
}
+
private void awaitServerStartup() throws Exception {
Instant started = Instant.now();
long elapsed = Duration.between(started, Instant.now()).toMillis();
@@ -240,7 +191,7 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
}
LOG.debug("tika test client failed to connect to server with status: {}", response.getStatus());
- } catch (javax.ws.rs.ProcessingException e) {
+ } catch (ProcessingException e) {
LOG.debug("tika test client failed to connect to server", e);
}
@@ -251,25 +202,28 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
elapsed + " ms");
}
- private JsonObject testOne(String fileName, boolean shouldFileExist) throws Exception {
+ private JsonNode sendAsync(List<String> fileNames) throws Exception {
awaitServerStartup();
+ List<FetchEmitTuple> tuples = new ArrayList<>();
+ for (String f : fileNames) {
+ tuples.add(getFetchEmitTuple(f));
+ }
+ String json = JsonFetchEmitTupleList.toJson(tuples);
+
Response response = WebClient
- .create(endPoint + "/emit")
+ .create(endPoint + "/async")
.accept("application/json")
- .post(getJsonString(fileName));
- if (shouldFileExist) {
- Path targFile = TMP_OUTPUT_DIR.resolve(fileName + ".json");
- assertTrue(Files.size(targFile) > 1);
- }
+ .post(json);
+ System.out.println("status: " + response.getStatus());
Reader reader = new InputStreamReader((InputStream) response.getEntity(), UTF_8);
- return JsonParser.parseReader(reader).getAsJsonObject();
+ return new ObjectMapper().readTree(reader);
}
- private String getJsonString(String fileName) {
- JsonObject root = new JsonObject();
- root.add("fetcher", new JsonPrimitive(FETCHER_NAME));
- root.add("fetchKey", new JsonPrimitive(fileName));
- root.add("emitter", new JsonPrimitive(EMITTER_NAME));
- return GSON.toJson(root);
+ private FetchEmitTuple getFetchEmitTuple(String fileName) throws IOException {
+ return new FetchEmitTuple(
+ new FetchKey(FETCHER_NAME, fileName),
+ new EmitKey(EMITTER_NAME, ""),
+ new Metadata(), ON_PARSE_EXCEPTION
+ );
}
}
diff --git a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java
index 554aee1..bea4cee 100644
--- a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java
+++ b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerEmitterIntegrationTest.java
@@ -16,13 +16,16 @@
*/
package org.apache.tika.server.core;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonPrimitive;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.serialization.JsonFetchEmitTuple;
+import org.apache.tika.pipes.emitter.EmitKey;
+import org.apache.tika.pipes.fetcher.FetchKey;
+import org.apache.tika.pipes.fetchiterator.FetchEmitTuple;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -32,23 +35,21 @@ import org.slf4j.LoggerFactory;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Response;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
-import java.util.List;
-import java.util.Random;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
@@ -58,14 +59,14 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
private static Path TMP_OUTPUT_DIR;
private static String TIKA_CONFIG_XML;
private static Path TIKA_CONFIG;
- private static Gson GSON = new GsonBuilder().create();
private static final String EMITTER_NAME = "fse";
private static final String FETCHER_NAME = "fsf";
- private static String[] FILES = new String[] {
+ private static String[] FILES = new String[]{
"hello_world.xml",
- "heavy_hang_30000.xml", "real_oom.xml", "system_exit.xml"
+ "heavy_hang_30000.xml", "real_oom.xml", "system_exit.xml",
+ "null_pointer.xml"
};
@BeforeClass
@@ -78,30 +79,30 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
for (String mockFile : FILES) {
Files.copy(TikaEmitterTest.class.getResourceAsStream(
- "/test-documents/mock/"+mockFile),
+ "/test-documents/mock/" + mockFile),
inputDir.resolve(mockFile));
}
TIKA_CONFIG = TMP_DIR.resolve("tika-config.xml");
- TIKA_CONFIG_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+
- "<properties>"+
- "<fetchers>"+
- "<fetcher class=\"org.apache.tika.pipes.fetcher.FileSystemFetcher\">"+
- "<params>"+
- "<param name=\"name\" type=\"string\">"+FETCHER_NAME+"</param>"+
- "<param name=\"basePath\" type=\"string\">"+inputDir.toAbsolutePath()+"</param>"+
- "</params>"+
- "</fetcher>"+
- "</fetchers>"+
- "<emitters>"+
- "<emitter class=\"org.apache.tika.pipes.emitter.fs.FileSystemEmitter\">"+
- "<params>"+
- "<param name=\"name\" type=\"string\">"+EMITTER_NAME+"</param>"+
-
- "<param name=\"basePath\" type=\"string\">"+ TMP_OUTPUT_DIR.toAbsolutePath()+"</param>"+
- "</params>"+
- "</emitter>"+
- "</emitters>"+
+ TIKA_CONFIG_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<properties>" +
+ "<fetchers>" +
+ "<fetcher class=\"org.apache.tika.pipes.fetcher.FileSystemFetcher\">" +
+ "<params>" +
+ "<param name=\"name\" type=\"string\">" + FETCHER_NAME + "</param>" +
+ "<param name=\"basePath\" type=\"string\">" + inputDir.toAbsolutePath() + "</param>" +
+ "</params>" +
+ "</fetcher>" +
+ "</fetchers>" +
+ "<emitters>" +
+ "<emitter class=\"org.apache.tika.pipes.emitter.fs.FileSystemEmitter\">" +
+ "<params>" +
+ "<param name=\"name\" type=\"string\">" + EMITTER_NAME + "</param>" +
+
+ "<param name=\"basePath\" type=\"string\">" + TMP_OUTPUT_DIR.toAbsolutePath() + "</param>" +
+ "</params>" +
+ "</emitter>" +
+ "</emitters>" +
"</properties>";
FileUtils.write(TIKA_CONFIG.toFile(), TIKA_CONFIG_XML, UTF_8);
@@ -124,7 +125,6 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
}
}
-
@Test
public void testBasic() throws Exception {
@@ -143,7 +143,69 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
};
serverThread.start();
try {
- testOne("hello_world.xml", true);
+ JsonNode node = testOne("hello_world.xml", true);
+ assertEquals("ok", node.get("status").asText());
+ } catch (Exception e) {
+ fail("shouldn't have an exception" + e.getMessage());
+ } finally {
+ serverThread.interrupt();
+ }
+ }
+
+ @Test
+ public void testNPEDefault() throws Exception {
+
+ Thread serverThread = new Thread() {
+ @Override
+ public void run() {
+ TikaServerCli.main(
+ new String[]{
+ "-enableUnsecureFeatures",
+ "-maxFiles", "2000",
+ "-p", INTEGRATION_TEST_PORT,
+ "-tmpFilePrefix", "basic-",
+ "-config", TIKA_CONFIG.toAbsolutePath().toString()
+ });
+ }
+ };
+ serverThread.start();
+ try {
+ JsonNode node = testOne("null_pointer.xml", true);
+ assertEquals("ok", node.get("status").asText());
+ assertContains("java.lang.NullPointerException",
+ node.get("parse_exception").asText());
+ } catch (Exception e) {
+ fail("shouldn't have an exception" + e.getMessage());
+ } finally {
+ serverThread.interrupt();
+ }
+ }
+
+ @Test
+ public void testNPESkip() throws Exception {
+
+ Thread serverThread = new Thread() {
+ @Override
+ public void run() {
+ TikaServerCli.main(
+ new String[]{
+ "-enableUnsecureFeatures",
+ "-maxFiles", "2000",
+ "-p", INTEGRATION_TEST_PORT,
+ "-tmpFilePrefix", "basic-",
+ "-config", TIKA_CONFIG.toAbsolutePath().toString()
+ });
+ }
+ };
+ serverThread.start();
+ try {
+ JsonNode node = testOne("null_pointer.xml", false,
+ FetchEmitTuple.ON_PARSE_EXCEPTION.SKIP);
+ assertEquals("ok", node.get("status").asText());
+ assertContains("java.lang.NullPointerException",
+ node.get("parse_exception").asText());
+ } catch (Exception e) {
+ fail("shouldn't have an exception" + e.getMessage());
} finally {
serverThread.interrupt();
}
@@ -192,8 +254,8 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
};
serverThread.start();
try {
- JsonObject response = testOne("real_oom.xml", false);
- assertContains("heap space", response.get("parse_error").getAsString());
+ JsonNode response = testOne("real_oom.xml", false);
+ assertContains("heap space", response.get("parse_error").asText());
} finally {
serverThread.interrupt();
}
@@ -218,8 +280,7 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
};
serverThread.start();
try {
- JsonObject response = testOne("heavy_hang_30000.xml", false);
- assertContains("heap space", response.get("parse_error").getAsString());
+ JsonNode response = testOne("heavy_hang_30000.xml", false);
} finally {
serverThread.interrupt();
}
@@ -228,14 +289,14 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
private void awaitServerStartup() throws Exception {
Instant started = Instant.now();
long elapsed = Duration.between(started, Instant.now()).toMillis();
- WebClient client = WebClient.create(endPoint+"/tika").accept("text/plain");
+ WebClient client = WebClient.create(endPoint + "/tika").accept("text/plain");
while (elapsed < MAX_WAIT_MS) {
try {
Response response = client.get();
if (response.getStatus() == 200) {
elapsed = Duration.between(started, Instant.now()).toMillis();
LOG.info("client observes server successfully started after " +
- elapsed+ " ms");
+ elapsed + " ms");
return;
}
LOG.debug("tika test client failed to connect to server with status: {}", response.getStatus());
@@ -250,26 +311,36 @@ public class TikaServerEmitterIntegrationTest extends IntegrationTestBase {
throw new TimeoutException("couldn't connect to server after " +
elapsed + " ms");
}
+ private JsonNode testOne(String fileName, boolean shouldFileExist) throws Exception {
+ return testOne(fileName, shouldFileExist, FetchEmitTuple.ON_PARSE_EXCEPTION.EMIT);
+ }
+
+ private JsonNode testOne(String fileName, boolean shouldFileExist, FetchEmitTuple.ON_PARSE_EXCEPTION onParseException) throws Exception {
- private JsonObject testOne(String fileName, boolean shouldFileExist) throws Exception {
awaitServerStartup();
Response response = WebClient
.create(endPoint + "/emit")
.accept("application/json")
- .post(getJsonString(fileName));
- if (shouldFileExist) {
+ .post(getJsonString(fileName, onParseException));
+ if (response.getStatus() == 200) {
Path targFile = TMP_OUTPUT_DIR.resolve(fileName + ".json");
- assertTrue(Files.size(targFile) > 1);
+ if (shouldFileExist) {
+ assertTrue(Files.size(targFile) > 1);
+ } else {
+ assertFalse(Files.isRegularFile(targFile));
+ }
+ Reader reader = new InputStreamReader((InputStream) response.getEntity(), UTF_8);
+ return new ObjectMapper().readTree(reader);
}
- Reader reader = new InputStreamReader((InputStream) response.getEntity(), UTF_8);
- return JsonParser.parseReader(reader).getAsJsonObject();
+ return null;
}
- private String getJsonString(String fileName) {
- JsonObject root = new JsonObject();
- root.add("fetcher", new JsonPrimitive(FETCHER_NAME));
- root.add("fetchKey", new JsonPrimitive(fileName));
- root.add("emitter", new JsonPrimitive(EMITTER_NAME));
- return GSON.toJson(root);
+ private String getJsonString(String fileName, FetchEmitTuple.ON_PARSE_EXCEPTION onParseException) throws IOException {
+ FetchEmitTuple t = new FetchEmitTuple(
+ new FetchKey(FETCHER_NAME, fileName),
+ new EmitKey(EMITTER_NAME, ""),
+ new Metadata(), onParseException
+ );
+ return JsonFetchEmitTuple.toJson(t);
}
}
diff --git a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerIntegrationTest.java b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerIntegrationTest.java
index 8d25d83..9e2d7d5 100644
--- a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerIntegrationTest.java
+++ b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerIntegrationTest.java
@@ -16,26 +16,24 @@
*/
package org.apache.tika.server.core;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import org.apache.cxf.common.logging.LogUtils;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.tika.TikaTest;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.serialization.JsonMetadataList;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Response;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.net.ConnectException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@@ -55,7 +53,6 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
private static final Logger LOG = LoggerFactory.getLogger(TikaServerIntegrationTest.class);
-
@Test
public void testBasic() throws Exception {
@@ -64,7 +61,7 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
public void run() {
TikaServerCli.main(
new String[]{
- "-maxFiles", "2000",
+ "-maxFiles", "100",
"-p", INTEGRATION_TEST_PORT,
"-tmpFilePrefix", "basic-"
});
@@ -203,13 +200,13 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
private String getServerId() throws Exception {
Response response = WebClient
- .create(endPoint + STATUS_PATH)
- .accept("application/json")
- .get();
+ .create(endPoint + STATUS_PATH)
+ .accept("application/json")
+ .get();
String jsonString =
CXFTestBase.getStringFromInputStream((InputStream) response.getEntity());
- JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
- return root.get("server_id").getAsJsonPrimitive().getAsString();
+ JsonNode root = new ObjectMapper().readTree(jsonString);
+ return root.get("server_id").asText();
}
private int getNumRestarts() throws Exception {
@@ -219,8 +216,8 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
.get();
String jsonString =
CXFTestBase.getStringFromInputStream((InputStream) response.getEntity());
- JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
- return root.get("num_restarts").getAsJsonPrimitive().getAsInt();
+ JsonNode root = new ObjectMapper().readTree(jsonString);
+ return root.get("num_restarts").intValue();
}
@Test
@@ -376,10 +373,10 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
awaitServerStartup();
Response response = WebClient
- .create(endPoint + META_PATH)
- .accept("application/json")
- .put(ClassLoader
- .getSystemResourceAsStream(TEST_STDOUT_STDERR));
+ .create(endPoint + META_PATH)
+ .accept("application/json")
+ .put(ClassLoader
+ .getSystemResourceAsStream(TEST_STDOUT_STDERR));
Reader reader = new InputStreamReader((InputStream) response.getEntity(), UTF_8);
List<Metadata> metadataList = JsonMetadataList.fromJson(reader);
assertEquals(1, metadataList.size());
@@ -436,7 +433,7 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
"-p", INTEGRATION_TEST_PORT,
"-taskTimeoutMillis", "10000", "-taskPulseMillis", "500",
"-pingPulseMillis", "100", "-maxRestarts", "0",
- "-JDlog4j.configuration=file:"+ LOG_FILE.toAbsolutePath(),
+ "-JDlog4j.configuration=file:" + LOG_FILE.toAbsolutePath(),
"-tmpFilePrefix", "tika-server-stderrlogging"
});
}
@@ -469,14 +466,14 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
private void awaitServerStartup() throws Exception {
Instant started = Instant.now();
long elapsed = Duration.between(started, Instant.now()).toMillis();
- WebClient client = WebClient.create(endPoint+"/tika").accept("text/plain");
+ WebClient client = WebClient.create(endPoint + "/tika").accept("text/plain");
while (elapsed < MAX_WAIT_MS) {
try {
Response response = client.get();
if (response.getStatus() == 200) {
elapsed = Duration.between(started, Instant.now()).toMillis();
LOG.info("client observes server successfully started after " +
- elapsed+ " ms");
+ elapsed + " ms");
return;
}
LOG.debug("tika test client failed to connect to server with status: {}", response.getStatus());
@@ -513,7 +510,7 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
awaitServerStartup();
Random r = new Random();
for (int i = 0; i < 100; i++) {
- System.out.println("FILE # "+i);
+ System.out.println("FILE # " + i);
boolean ex = false;
Response response = null;
String file = TEST_HELLO_WORLD;
@@ -525,7 +522,7 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
} else if (r.nextFloat() < 0.02) {
file = TEST_HEAVY_HANG;
}
- System.out.println("about to process: "+file);
+ System.out.println("about to process: " + file);
response = WebClient
.create(endPoint + META_PATH)
.accept("application/json")
@@ -556,16 +553,29 @@ public class TikaServerIntegrationTest extends IntegrationTestBase {
}
private void testBaseline() throws Exception {
- awaitServerStartup();
- Response response = WebClient
- .create(endPoint + META_PATH)
- .accept("application/json")
- .put(ClassLoader
- .getSystemResourceAsStream(TEST_HELLO_WORLD));
- Reader reader = new InputStreamReader((InputStream) response.getEntity(), UTF_8);
- List<Metadata> metadataList = JsonMetadataList.fromJson(reader);
- assertEquals(1, metadataList.size());
- assertEquals("Nikolai Lobachevsky", metadataList.get(0).get("author"));
- assertContains("hello world", metadataList.get(0).get("X-TIKA:content"));
+ int maxTries = 3;
+ int tries = 0;
+ while (++tries < maxTries) {
+ awaitServerStartup();
+ Response response = null;
+
+ try {
+ response = WebClient
+ .create(endPoint + META_PATH)
+ .accept("application/json")
+ .put(ClassLoader
+ .getSystemResourceAsStream(TEST_HELLO_WORLD));
+ } catch (ProcessingException e) {
+ continue;
+ }
+ if (response.getStatus() == 503) {
+ continue;
+ }
+ Reader reader = new InputStreamReader((InputStream) response.getEntity(), UTF_8);
+ List<Metadata> metadataList = JsonMetadataList.fromJson(reader);
+ assertEquals(1, metadataList.size());
+ assertEquals("Nikolai Lobachevsky", metadataList.get(0).get("author"));
+ assertContains("hello world", metadataList.get(0).get("X-TIKA:content"));
+ }
}
}
diff --git a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerStatusTest.java b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerStatusTest.java
index 556ac01..d4b6c6d 100644
--- a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerStatusTest.java
+++ b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerStatusTest.java
@@ -16,13 +16,11 @@
*/
package org.apache.tika.server.core;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
-import org.apache.tika.server.core.CXFTestBase;
-import org.apache.tika.server.core.ServerStatus;
import org.apache.tika.server.core.resource.TikaServerStatus;
import org.apache.tika.server.core.writer.JSONObjWriter;
import org.junit.Test;
@@ -59,15 +57,15 @@ public class TikaServerStatusTest extends CXFTestBase {
Response response = WebClient.create(endPoint + STATUS_PATH).get();
String jsonString =
getStringFromInputStream((InputStream) response.getEntity());
- JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
+ JsonNode root = new ObjectMapper().readTree(jsonString);
assertTrue(root.has("server_id"));
assertTrue(root.has("status"));
assertTrue(root.has("millis_since_last_parse_started"));
assertTrue(root.has("files_processed"));
- assertEquals("OPERATING", root.getAsJsonPrimitive("status").getAsString());
- assertEquals(0, root.getAsJsonPrimitive("files_processed").getAsInt());
- long millis = root.getAsJsonPrimitive("millis_since_last_parse_started").getAsInt();
+ assertEquals("OPERATING", root.get("status").asText());
+ assertEquals(0, root.get("files_processed").intValue());
+ long millis = root.get("millis_since_last_parse_started").longValue();
assertTrue(millis > 0 && millis < 360000);
- assertEquals(SERVER_ID, root.getAsJsonPrimitive("server_id").getAsString());
+ assertEquals(SERVER_ID, root.get("server_id").asText());
}
}