From d79f57c8fe9a13f8bb549777d82ce5be0034acb1 Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Fri, 2 Oct 2015 18:15:22 +0530 Subject: [PATCH 01/19] PoT definitions --- .../parser/pot/PooledTimeSeriesParser.java | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java new file mode 100644 index 0000000000..35098142c8 --- /dev/null +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -0,0 +1,123 @@ +package org.apache.tika.parser.pot; + +import org.apache.tika.exception.TikaException; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.mime.MediaType; +import org.apache.tika.parser.AbstractParser; +import org.apache.tika.parser.ParseContext; +import org.apache.tika.sax.XHTMLContentHandler; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by Aditya on 9/15/15. + */ +public class PooledTimeSeriesParser extends AbstractParser { + + private static final Set SUPPORTED_TYPES = Collections.unmodifiableSet( + new HashSet(Arrays.asList(new MediaType[]{ + MediaType.video("avi"), MediaType.video("mpeg4") + // TODO: Add all supported video types + }))); + + + // check if opencv is present + private boolean hasOpenCV() { + // TODO + return false; + } + + /** + * Returns the set of media types supported by this parser when used + * with the given parse context. + * + * @param context parse context + * @return immutable set of media types + * @since Apache Tika 0.7 + */ + @Override + public Set getSupportedTypes(ParseContext context) { + + // TODO + // Check PooledTImeSeries configs to see if OpenCV is installed + // if yes, then advertise video mime types + // return SUPPORTED_TYPES; + // else return Collections.empty() + } + + /** + * Parses a document stream into a sequence of XHTML SAX events. + * Fills in related document metadata in the given metadata object. + *

+ * The given document stream is consumed but not closed by this method. + * The responsibility to close the stream remains on the caller. + *

+ * Information about the parsing context can be passed in the context + * parameter. See the parser implementations for the kinds of context + * information they expect. + * + * @param stream the document stream (input) + * @param handler handler for the XHTML SAX events (output) + * @param metadata document metadata (input and output) + * @param context parse context + * @throws IOException if the document stream could not be read + * @throws SAXException if the SAX events could not be processed + * @throws TikaException if the document could not be parsed + * @since Apache Tika 0.5 + */ + @Override + public void parse(InputStream stream, ContentHandler handler, Metadata metadata, ParseContext context) throws IOException, SAXException, TikaException { + + // TODO + // Setup deps/pre-rqs + computePoT(); + } + + private void computePoT((File input, File output /* TODO PooledTimeSeriesConfig() */) throws IOException, TikaException { + + // TODO + // formulate cmd for PoT.java + // Question: Should we integrate the PoT code into Tika itself, + // and handoff the inputstream to an instance of PoT? + // (As opposed to invoking it form the cmd line) + + doExtract(); + + } + + + /** + * Reads the contents of the given stream and write it to the given XHTML + * content handler. The stream is closed once fully processed. + * + * @param stream + * Stream where is the result of ocr + * @param xhtml + * XHTML content handler + * @throws SAXException + * if the XHTML SAX events could not be handled + * @throws IOException + * if an input error occurred + */ + private void doExtract(InputStream stream, XHTMLContentHandler xhtml) { + // TODO + xhtml.startDocument(); + + xhtml.startElement("table"); + // TODO : extract feature vector from PoT output + // - i.e OF.txt and HOG.txt + + xhtml.endElement("table"); + xhtml.endDocument(); + } + + +} From 78daf1a0cd30b4810f64582582a873cd1c5f81ce Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Sun, 11 Oct 2015 22:09:56 -0400 Subject: [PATCH 02/19] PoT Config defns --- .../parser/pot/PooledTimeSeriesConfig.java | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java new file mode 100644 index 0000000000..1ecf48fc6f --- /dev/null +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java @@ -0,0 +1,176 @@ +package org.apache.tika.parser.pot; + +/** + * Created by Aditya on 9/29/15. + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Locale; +import java.util.Properties; + +/** + * Configuration for PooledTimeSeriesParser. + * + * This allows to enable PooledTimeSeriesParser and set its parameters: + *

+ * PooledTimeSeriesConfig config = new PooledTimeSeriesConfig();
+ * config.setOpenCVPath(opencvFolder);
+ * parseContext.set(PooledTimeSeriesConfig.class, config);
+ *

+ * + * Parameters can also be set by either editing the existing PooledTimeSeriesConfig.properties file in, + * tika-parser/src/main/resources/org/apache/tika/parser/pot, or overriding it by creating your own + * and placing it in the package org/apache/tika/parser/pot on the classpath. + * + */ +public class PooledTimeSeriesConfig implements Serializable { + + private static final long serialVersionUID = -4861942486845757891L; + + // Path to OpenCV installation folder, if not on system path. + private String opencvPath = ""; + + // Minimum file size to submit file to ocr. + private int minFileSizeForPoT = 0; + + // Maximum file size to submit file to ocr. + private int maxFileSizeForPoT = Integer.MAX_VALUE; + + // Maximum time (seconds) to wait for the pot-ing process termination + private int timeout = 120; + + /** + * Default contructor. + */ + public PooledTimeSeriesConfig() { + init(this.getClass().getResourceAsStream("PooledTimeSeriesConfig.properties")); + } + + /** + * Loads properties from InputStream and then tries to close InputStream. + * If there is an IOException, this silently swallows the exception + * and goes back to the default. + * + * @param is + */ + public PooledTimeSeriesConfig(InputStream is) { + init(is); + } + + private void init(InputStream is) { + if (is == null) { + return; + } + Properties props = new Properties(); + try { + props.load(is); + } catch (IOException e) { + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + //swallow + } + } + } + + setOpenCVPath( + getProp(props, "opencvPath", getOpenCVPath())); + setMinFileSizeForPoT( + getProp(props, "minFileSizeForPoT", getMinFileSizeForPoT())); + setMaxFileSizeForPoT( + getProp(props, "maxFileSizeForPoT", getMaxFileSizeForPoT())); + setTimeout( + getProp(props, "timeout", getTimeout())); + + } + + /** @see #setOpenCVPath(String tesseractPath)*/ + public String getOpenCVPath() { + return opencvPath; + } + + /** + * Set the path to the OpenCV executable, needed if it is not on system path. + */ + public void setOpenCVPath(String opencvPath) { + if(!opencvPath.isEmpty() && !opencvPath.endsWith(File.separator)) + opencvPath += File.separator; + + this.opencvPath = opencvPath; + } + + /** @see #setMinFileSizeForPoT (int minFileSizeToOcr)*/ + public int getMinFileSizeForPoT() { + return minFileSizeForPoT; + } + + /** + * Set minimum file size to submit file to pot. + * Default is 0. + */ + public void setMinFileSizeForPoT(int minFileSizeForPoT) { + this.minFileSizeForPoT = minFileSizeForPoT; + } + + /** @see #setMaxFileSizeForPoT (int maxFileSizeToOcr)*/ + public int getMaxFileSizeForPoT() { + return maxFileSizeForPoT; + } + + /** + * Set maximum file size to submit file to ocr. + * Default is Integer.MAX_VALUE. + */ + public void setMaxFileSizeForPoT(int maxFileSizeToOcr) { + this.maxFileSizeForPoT = maxFileSizeForPoT; + } + + /** + * Set maximum time (seconds) to wait for the pooled time series process to terminate. + * Default value is 120s. + */ + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + /** @see #setTimeout(int timeout)*/ + public int getTimeout() { + return timeout; + } + + /** + * Get property from the properties file passed in. + * @param properties properties file to read from. + * @param property the property to fetch. + * @param defaultMissing default parameter to use. + * @return the value. + */ + private int getProp(Properties properties, String property, int defaultMissing) { + String p = properties.getProperty(property); + if (p == null || p.isEmpty()){ + return defaultMissing; + } + try { + return Integer.parseInt(p); + } catch (Throwable ex) { + throw new RuntimeException(String.format(Locale.ROOT, "Cannot parse PooledTimeSeriesConfig variable %s, invalid integer value", + property), ex); + } + } + + /** + * Get property from the properties file passed in. + * @param properties properties file to read from. + * @param property the property to fetch. + * @param defaultMissing default parameter to use. + * @return the value. + */ + private String getProp(Properties properties, String property, String defaultMissing) { + return properties.getProperty(property, defaultMissing); + } +} From 9923a7c0a8dc7338b845e314c9caa20f0b8142af Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Wed, 14 Oct 2015 10:43:04 -0400 Subject: [PATCH 03/19] Registered PoTParser with ParserServices --- .../tika/parser/pot/PooledTimeSeriesParser.java | 12 +++++++----- .../META-INF/services/org.apache.tika.parser.Parser | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 35098142c8..38cf51195d 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -24,7 +24,7 @@ public class PooledTimeSeriesParser extends AbstractParser { private static final Set SUPPORTED_TYPES = Collections.unmodifiableSet( new HashSet(Arrays.asList(new MediaType[]{ - MediaType.video("avi"), MediaType.video("mpeg4") + MediaType.video("avi"), MediaType.video("mp4") // TODO: Add all supported video types }))); @@ -51,6 +51,8 @@ public Set getSupportedTypes(ParseContext context) { // if yes, then advertise video mime types // return SUPPORTED_TYPES; // else return Collections.empty() + + return Collections.emptySet(); } /** @@ -78,10 +80,10 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, // TODO // Setup deps/pre-rqs - computePoT(); + // computePoT(); } - private void computePoT((File input, File output /* TODO PooledTimeSeriesConfig() */) throws IOException, TikaException { + private void computePoT(File input, File output /* TODO PooledTimeSeriesConfig() */) throws IOException, TikaException { // TODO // formulate cmd for PoT.java @@ -89,7 +91,7 @@ private void computePoT((File input, File output /* TODO PooledTimeSeriesConfig( // and handoff the inputstream to an instance of PoT? // (As opposed to invoking it form the cmd line) - doExtract(); + // doExtract(); } @@ -107,7 +109,7 @@ private void computePoT((File input, File output /* TODO PooledTimeSeriesConfig( * @throws IOException * if an input error occurred */ - private void doExtract(InputStream stream, XHTMLContentHandler xhtml) { + private void doExtract(InputStream stream, XHTMLContentHandler xhtml) throws SAXException, IOException { // TODO xhtml.startDocument(); diff --git a/tika-parsers/src/main/resources/META-INF/services/org.apache.tika.parser.Parser b/tika-parsers/src/main/resources/META-INF/services/org.apache.tika.parser.Parser index ba5884801f..a1a692f17c 100644 --- a/tika-parsers/src/main/resources/META-INF/services/org.apache.tika.parser.Parser +++ b/tika-parsers/src/main/resources/META-INF/services/org.apache.tika.parser.Parser @@ -60,6 +60,7 @@ org.apache.tika.parser.code.SourceCodeParser org.apache.tika.parser.mat.MatParser org.apache.tika.parser.ocr.TesseractOCRParser org.apache.tika.parser.gdal.GDALParser +org.apache.tika.parser.pot.PooledTimeSeriesParser org.apache.tika.parser.grib.GribParser org.apache.tika.parser.jdbc.SQLite3Parser org.apache.tika.parser.isatab.ISArchiveParser From a76b6c643a55a84c310d5bfea0ab799d13a1d8a9 Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Wed, 14 Oct 2015 11:30:40 -0400 Subject: [PATCH 04/19] defined PoT properties config file --- .../org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties diff --git a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties new file mode 100644 index 0000000000..e69de29bb2 From ca8c1811fea9f45ead9c1dc60ba566befafd374d Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Wed, 14 Oct 2015 11:32:31 -0400 Subject: [PATCH 05/19] defined PoT config values --- .../pot/PooledTimeSeriesConfig.properties | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties index e69de29bb2..28285a0980 100644 --- a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties +++ b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties @@ -0,0 +1,17 @@ +# 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. + +opencvPath=/usr/local/share/OpenCV/java/ +pooledTimeSeriesPath=/Users/Aditya/Projects/pooled_time_series/ From 1012ba1e68939d4ab3784043694ef4a26b27e3af Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Wed, 14 Oct 2015 11:33:33 -0400 Subject: [PATCH 06/19] Modified config file to better reflect PoT config values --- .../parser/pot/PooledTimeSeriesConfig.java | 41 ++++--------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java index 1ecf48fc6f..6247e0b8fe 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java @@ -33,14 +33,11 @@ public class PooledTimeSeriesConfig implements Serializable { // Path to OpenCV installation folder, if not on system path. private String opencvPath = ""; - // Minimum file size to submit file to ocr. - private int minFileSizeForPoT = 0; - - // Maximum file size to submit file to ocr. - private int maxFileSizeForPoT = Integer.MAX_VALUE; + // Path to PooledTimeSeries program + private String pooledTimeSeriesPath = ""; // Maximum time (seconds) to wait for the pot-ing process termination - private int timeout = 120; + private int timeout = 84600; /** * Default contructor. @@ -80,10 +77,8 @@ private void init(InputStream is) { setOpenCVPath( getProp(props, "opencvPath", getOpenCVPath())); - setMinFileSizeForPoT( - getProp(props, "minFileSizeForPoT", getMinFileSizeForPoT())); - setMaxFileSizeForPoT( - getProp(props, "maxFileSizeForPoT", getMaxFileSizeForPoT())); + setPooledTimeSeriesPath( + getProp(props, "pooledTimeSeriesPath", getOpenCVPath())); setTimeout( getProp(props, "timeout", getTimeout())); @@ -104,30 +99,12 @@ public void setOpenCVPath(String opencvPath) { this.opencvPath = opencvPath; } - /** @see #setMinFileSizeForPoT (int minFileSizeToOcr)*/ - public int getMinFileSizeForPoT() { - return minFileSizeForPoT; - } - - /** - * Set minimum file size to submit file to pot. - * Default is 0. - */ - public void setMinFileSizeForPoT(int minFileSizeForPoT) { - this.minFileSizeForPoT = minFileSizeForPoT; + public String getPooledTimeSeriesPath() { + return pooledTimeSeriesPath; } - /** @see #setMaxFileSizeForPoT (int maxFileSizeToOcr)*/ - public int getMaxFileSizeForPoT() { - return maxFileSizeForPoT; - } - - /** - * Set maximum file size to submit file to ocr. - * Default is Integer.MAX_VALUE. - */ - public void setMaxFileSizeForPoT(int maxFileSizeToOcr) { - this.maxFileSizeForPoT = maxFileSizeForPoT; + public void setPooledTimeSeriesPath(String pooledTimeSeriesPath) { + this.pooledTimeSeriesPath = pooledTimeSeriesPath; } /** From d3f78b567d22e1626dcd7ceea624e789fe3057ef Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Wed, 14 Oct 2015 11:34:13 -0400 Subject: [PATCH 07/19] Fixed build errors --- .../parser/pot/PooledTimeSeriesParser.java | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 38cf51195d..1fc2570aee 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -1,6 +1,8 @@ package org.apache.tika.parser.pot; import org.apache.tika.exception.TikaException; +import org.apache.tika.io.TemporaryResources; +import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.AbstractParser; @@ -10,6 +12,7 @@ import org.xml.sax.SAXException; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -52,7 +55,8 @@ public Set getSupportedTypes(ParseContext context) { // return SUPPORTED_TYPES; // else return Collections.empty() - return Collections.emptySet(); + // FIXME: Resolve above TODO and remove this return statement + return SUPPORTED_TYPES; } /** @@ -80,7 +84,36 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, // TODO // Setup deps/pre-rqs - // computePoT(); + + // TODO: Check for PooledTImeSeries and OpenCV + // if ( !hasOpenCV()) { + // return; + // } + // + + XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); + + TemporaryResources tmp = new TemporaryResources(); + File output = null; + try { + TikaInputStream tikaStream = TikaInputStream.get(stream, tmp); + File input = tikaStream.getFile(); + + //long size = tikaStream.getLength(); + + output = tmp.createTemporaryFile(); + + computePoT(input, output); + + doExtract(new FileInputStream(output), xhtml); + + } + finally { + tmp.dispose(); + if (output != null) { + output.delete(); + } + } } private void computePoT(File input, File output /* TODO PooledTimeSeriesConfig() */) throws IOException, TikaException { @@ -90,9 +123,6 @@ private void computePoT(File input, File output /* TODO PooledTimeSeriesConfig() // Question: Should we integrate the PoT code into Tika itself, // and handoff the inputstream to an instance of PoT? // (As opposed to invoking it form the cmd line) - - // doExtract(); - } From 43969b154a83cfb3dad29eb49f597426c88bcfb4 Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Thu, 29 Oct 2015 12:17:25 -0400 Subject: [PATCH 08/19] Built basic version of tika-pot-parser --- .../parser/pot/PooledTimeSeriesParser.java | 85 ++++++++++++++++++- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 1fc2570aee..3e84c9b53e 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -13,18 +13,35 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.LogFactory; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.tika.io.TemporaryResources; +import org.apache.tika.io.TikaInputStream; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Created by Aditya on 9/15/15. */ public class PooledTimeSeriesParser extends AbstractParser { - + private static final PooledTimeSeriesConfig DEFAULT_CONFIG = new PooledTimeSeriesConfig(); private static final Set SUPPORTED_TYPES = Collections.unmodifiableSet( new HashSet(Arrays.asList(new MediaType[]{ MediaType.video("avi"), MediaType.video("mp4") @@ -84,6 +101,8 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, // TODO // Setup deps/pre-rqs + PooledTimeSeriesConfig config = context.get(PooledTimeSeriesConfig.class, DEFAULT_CONFIG); + // TODO: Check for PooledTImeSeries and OpenCV // if ( !hasOpenCV()) { @@ -103,7 +122,11 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, output = tmp.createTemporaryFile(); - computePoT(input, output); + computePoT(input, output, config); + + // Output is same as inputfilename with .of.txt as suffix + // TODO: Repeast for .hog.txt + output = new File(input.getAbsoluteFile() + ".of.txt"); doExtract(new FileInputStream(output), xhtml); @@ -116,13 +139,60 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, } } - private void computePoT(File input, File output /* TODO PooledTimeSeriesConfig() */) throws IOException, TikaException { + private void computePoT(File input, File output, PooledTimeSeriesConfig config) throws IOException, TikaException { // TODO // formulate cmd for PoT.java // Question: Should we integrate the PoT code into Tika itself, // and handoff the inputstream to an instance of PoT? // (As opposed to invoking it form the cmd line) + + + String[] cmd = {"java","-Djava.library.path ", config.getOpenCVPath(), " -jar " + , config.getPooledTimeSeriesPath() + getPooledTimeSeriesProg(), + input.getPath() + }; + + + System.out.println(Arrays.asList(cmd)); + + ProcessBuilder pb = new ProcessBuilder(cmd); + final Process process = pb.start(); + + process.getOutputStream().close(); + InputStream out = process.getInputStream(); + InputStream err = process.getErrorStream(); + + //logStream("OCR MSG", out, input); + //logStream("OCR ERROR", err, input); + + FutureTask waitTask = new FutureTask(new Callable() { + public Integer call() throws Exception { + return process.waitFor(); + } + }); + + Thread waitThread = new Thread(waitTask); + waitThread.start(); + + try { + waitTask.get(config.getTimeout(), TimeUnit.SECONDS); + + } catch (InterruptedException e) { + waitThread.interrupt(); + process.destroy(); + Thread.currentThread().interrupt(); + throw new TikaException("PooledTimeSeriesParser interrupted", e); + + } catch (ExecutionException e) { + // should not be thrown + + } catch (TimeoutException e) { + waitThread.interrupt(); + process.destroy(); + throw new TikaException("PooledTimeSeriesParser timeout", e); + } + } @@ -147,9 +217,18 @@ private void doExtract(InputStream stream, XHTMLContentHandler xhtml) throws SAX // TODO : extract feature vector from PoT output // - i.e OF.txt and HOG.txt + BufferedReader reader = new BufferedReader(new InputStreamReader(stream, UTF_8)); + String line = reader.readLine(); + + xhtml.characters(line); + xhtml.endElement("table"); xhtml.endDocument(); } + static String getPooledTimeSeriesProg() { + // TODO: Seperate out target/ folder from excutable jar + return "target/pooled-time-series-1.0-SNAPSHOT-jar-with-dependencies.jar"; + } } From 30f240abfe5b0be9fd572e0d55be764d43827412 Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Fri, 13 Nov 2015 21:06:33 -0500 Subject: [PATCH 09/19] Added a timeout value --- .../org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties index 28285a0980..a65f9585eb 100644 --- a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties +++ b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties @@ -15,3 +15,4 @@ opencvPath=/usr/local/share/OpenCV/java/ pooledTimeSeriesPath=/Users/Aditya/Projects/pooled_time_series/ +timeout=120 \ No newline at end of file From 3c9719370a62c12e31fa744e4ec9547c83ac2ca6 Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Fri, 13 Nov 2015 21:07:54 -0500 Subject: [PATCH 10/19] Parser now runs PoT and extracts OF metadata Uses JavaProcessBuilder to invoke the PoT jar. Runs PoT to generate of.txt and hog.txt. Extracts of.txt metadata as a list of lists, i.e. a 2D matrix in HTML --- tika-parsers/pom.xml | 7 + .../parser/pot/PooledTimeSeriesParser.java | 155 +++++++++++------- 2 files changed, 99 insertions(+), 63 deletions(-) diff --git a/tika-parsers/pom.xml b/tika-parsers/pom.xml index aef1cf27cc..945130cb3e 100644 --- a/tika-parsers/pom.xml +++ b/tika-parsers/pom.xml @@ -361,6 +361,13 @@ 3.2.2 provided + + + + in.jlibs + jlibs-core + 2.1 + diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 3e84c9b53e..be1e7052da 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -8,6 +8,7 @@ import org.apache.tika.parser.AbstractParser; import org.apache.tika.parser.ParseContext; import org.apache.tika.sax.XHTMLContentHandler; +import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; @@ -18,6 +19,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; +import java.io.Reader; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.LogFactory; @@ -30,11 +32,15 @@ import org.apache.tika.io.TemporaryResources; import org.apache.tika.io.TikaInputStream; +import org.xml.sax.helpers.AttributesImpl; + import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; +import jlibs.core.lang.JavaProcessBuilder; import static java.nio.charset.StandardCharsets.UTF_8; /** @@ -139,63 +145,73 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, } } - private void computePoT(File input, File output, PooledTimeSeriesConfig config) throws IOException, TikaException { - - // TODO - // formulate cmd for PoT.java - // Question: Should we integrate the PoT code into Tika itself, - // and handoff the inputstream to an instance of PoT? - // (As opposed to invoking it form the cmd line) - - - String[] cmd = {"java","-Djava.library.path ", config.getOpenCVPath(), " -jar " - , config.getPooledTimeSeriesPath() + getPooledTimeSeriesProg(), - input.getPath() - }; - - - System.out.println(Arrays.asList(cmd)); - - ProcessBuilder pb = new ProcessBuilder(cmd); - final Process process = pb.start(); - - process.getOutputStream().close(); - InputStream out = process.getInputStream(); - InputStream err = process.getErrorStream(); - - //logStream("OCR MSG", out, input); - //logStream("OCR ERROR", err, input); + private void computePoT(File input, File output, PooledTimeSeriesConfig config) throws IOException, TikaException { + JavaProcessBuilder jvm = new JavaProcessBuilder(); + //jvm.javaHome(new File("/Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home")); // configure java home + jvm.javaHome(new File(System.getProperty("java.home"))); // configure java home + jvm.workingDir(new File(config.getPooledTimeSeriesPath())); // to configure working directory to configure various attributes: + + // to configure heap and vmtype + jvm.initialHeap(512); // or jvm.initialHeap("512m"); + jvm.maxHeap(1024); // or jvm.maxHeap("1024m"); + + jvm.jvmArg("-jar"); + jvm.jvmArg(getPooledTimeSeriesProg()); + + jvm.libraryPath(config.getOpenCVPath()); + + jvm.jvmArg("-f"); + jvm.jvmArg(input.getPath()); + + + Process process; + try { + String command[] = jvm.command(); + process = jvm.launch(System.out, System.err); + process.waitFor(); + + process.getOutputStream().close(); + InputStream out = process.getInputStream(); + InputStream err = process.getErrorStream(); + + logStream("POT MSG", out, input); + logStream("POT ERROR", err, input); + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } - FutureTask waitTask = new FutureTask(new Callable() { - public Integer call() throws Exception { - return process.waitFor(); + /** + * Starts a thread that reads the contents of the standard output or error + * stream of the given process to not block the process. The stream is closed + * once fully processed. + */ + private void logStream(final String logType, final InputStream stream, final File file) { + new Thread() { + public void run() { + Reader reader = new InputStreamReader(stream, UTF_8); + StringBuilder out = new StringBuilder(); + char[] buffer = new char[1024]; + try { + for (int n = reader.read(buffer); n != -1; n = reader.read(buffer)) + out.append(buffer, 0, n); + } catch (IOException e) { + + } finally { + IOUtils.closeQuietly(stream); + } + + String msg = out.toString(); + LogFactory.getLog(PooledTimeSeriesParser.class).debug(msg); } - }); - - Thread waitThread = new Thread(waitTask); - waitThread.start(); - - try { - waitTask.get(config.getTimeout(), TimeUnit.SECONDS); - - } catch (InterruptedException e) { - waitThread.interrupt(); - process.destroy(); - Thread.currentThread().interrupt(); - throw new TikaException("PooledTimeSeriesParser interrupted", e); - - } catch (ExecutionException e) { - // should not be thrown - - } catch (TimeoutException e) { - waitThread.interrupt(); - process.destroy(); - throw new TikaException("PooledTimeSeriesParser timeout", e); - } - + }.start(); } - /** * Reads the contents of the given stream and write it to the given XHTML * content handler. The stream is closed once fully processed. @@ -210,19 +226,32 @@ public Integer call() throws Exception { * if an input error occurred */ private void doExtract(InputStream stream, XHTMLContentHandler xhtml) throws SAXException, IOException { - // TODO - xhtml.startDocument(); - - xhtml.startElement("table"); - // TODO : extract feature vector from PoT output - // - i.e OF.txt and HOG.txt BufferedReader reader = new BufferedReader(new InputStreamReader(stream, UTF_8)); String line = reader.readLine(); - - xhtml.characters(line); - - xhtml.endElement("table"); + String[] firstLine = line.split(" "); + String frames = firstLine[0]; + String vecSize = firstLine[1]; + + AttributesImpl attributes = new AttributesImpl(); + attributes.addAttribute("", "", "numRows", "CDATA", frames); + attributes.addAttribute("", "", "numCols", "CDATA", vecSize); + + xhtml.startDocument(); + xhtml.startElement("div", attributes); + + xhtml.startElement("ol"); + while ((line = reader.readLine()) != null) { + xhtml.startElement("ol"); + for (String val : line.split(" ")) { + xhtml.startElement("li"); + xhtml.characters(val); + xhtml.endElement("li"); + } + xhtml.endElement("ol"); + } + xhtml.endElement("ol"); + xhtml.endDocument(); } From 90e42d145d806cc2b122baf8f7b12a4b465c5125 Mon Sep 17 00:00:00 2001 From: Aditya Dhulipala Date: Fri, 13 Nov 2015 21:22:46 -0500 Subject: [PATCH 11/19] Added Apache License header --- .../tika/parser/pot/PooledTimeSeriesParser.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index be1e7052da..8377d35aab 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -1,3 +1,19 @@ +/* + * 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.parser.pot; import org.apache.tika.exception.TikaException; From 54c3df51355d48d338656d21cf043d0d7e28d2e0 Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Wed, 25 Nov 2015 21:52:33 -0800 Subject: [PATCH 12/19] Update ALv2 header. Remove comments. Clean up code. Generalize properties. --- .../parser/pot/PooledTimeSeriesConfig.java | 21 +++++++++++++++---- .../parser/pot/PooledTimeSeriesParser.java | 11 ++-------- .../pot/PooledTimeSeriesConfig.properties | 4 ++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java index 6247e0b8fe..147f6dba5b 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java @@ -1,9 +1,22 @@ -package org.apache.tika.parser.pot; - -/** - * Created by Aditya on 9/29/15. +/* + * 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.parser.pot; + import java.io.File; import java.io.IOException; import java.io.InputStream; diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 8377d35aab..a6f4d30b81 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.tika.parser.pot; import org.apache.tika.exception.TikaException; @@ -59,9 +60,7 @@ import jlibs.core.lang.JavaProcessBuilder; import static java.nio.charset.StandardCharsets.UTF_8; -/** - * Created by Aditya on 9/15/15. - */ + public class PooledTimeSeriesParser extends AbstractParser { private static final PooledTimeSeriesConfig DEFAULT_CONFIG = new PooledTimeSeriesConfig(); private static final Set SUPPORTED_TYPES = Collections.unmodifiableSet( @@ -163,7 +162,6 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, private void computePoT(File input, File output, PooledTimeSeriesConfig config) throws IOException, TikaException { JavaProcessBuilder jvm = new JavaProcessBuilder(); - //jvm.javaHome(new File("/Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home")); // configure java home jvm.javaHome(new File(System.getProperty("java.home"))); // configure java home jvm.workingDir(new File(config.getPooledTimeSeriesPath())); // to configure working directory to configure various attributes: @@ -271,9 +269,4 @@ private void doExtract(InputStream stream, XHTMLContentHandler xhtml) throws SAX xhtml.endDocument(); } - static String getPooledTimeSeriesProg() { - // TODO: Seperate out target/ folder from excutable jar - return "target/pooled-time-series-1.0-SNAPSHOT-jar-with-dependencies.jar"; - } - } diff --git a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties index a65f9585eb..f41d32a03d 100644 --- a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties +++ b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties @@ -13,6 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -opencvPath=/usr/local/share/OpenCV/java/ -pooledTimeSeriesPath=/Users/Aditya/Projects/pooled_time_series/ +opencvPath=/path/to/opencv/java/ +pooledTimeSeriesPath=/path/to/pooled_time_series/ timeout=120 \ No newline at end of file From 161603eaad0ebc5628e4d723c8ccc5ebef892ebb Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Wed, 25 Nov 2015 22:15:00 -0800 Subject: [PATCH 13/19] generalize property to refer to jar file. --- .../java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java | 2 +- .../apache/tika/parser/pot/PooledTimeSeriesConfig.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index a6f4d30b81..b7bc304e24 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -170,7 +170,7 @@ private void computePoT(File input, File output, PooledTimeSeriesConfig config) jvm.maxHeap(1024); // or jvm.maxHeap("1024m"); jvm.jvmArg("-jar"); - jvm.jvmArg(getPooledTimeSeriesProg()); + jvm.jvmArg(config.getPooledTimeSeriesPath()); jvm.libraryPath(config.getOpenCVPath()); diff --git a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties index f41d32a03d..294f4503b1 100644 --- a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties +++ b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties @@ -14,5 +14,5 @@ # limitations under the License. opencvPath=/path/to/opencv/java/ -pooledTimeSeriesPath=/path/to/pooled_time_series/ +pooledTimeSeriesPath=/path/to/pooled_time_series.jar timeout=120 \ No newline at end of file From 3e3fcc772035d2f70745202e2b295748cda099db Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Wed, 25 Nov 2015 22:49:33 -0800 Subject: [PATCH 14/19] handle tika-bundle updates for OSGI for PoTParser --- tika-bundle/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tika-bundle/pom.xml b/tika-bundle/pom.xml index d0968a66e0..438beb0554 100644 --- a/tika-bundle/pom.xml +++ b/tika-bundle/pom.xml @@ -186,6 +186,7 @@ javax.xml.stream.events;version="[1.0,2)";resolution:=optional, javax.xml.stream.util;version="[1.0,2)";resolution:=optional, javax.ws.rs.core;resolution:=optional, + jlibs.core.lang;resolution:=optional, net.sf.ehcache;resolution:=optional, nu.xom;resolution:=optional, opendap.dap.http;resolution:=optional, From 6c6e18f8bfca11fb347ed9254ae7c24342348da2 Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Thu, 26 Nov 2015 07:53:58 -0800 Subject: [PATCH 15/19] Use the parent directory as the CWD for executing the PoT command. --- .../java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index b7bc304e24..1936441b69 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -163,7 +163,7 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, private void computePoT(File input, File output, PooledTimeSeriesConfig config) throws IOException, TikaException { JavaProcessBuilder jvm = new JavaProcessBuilder(); jvm.javaHome(new File(System.getProperty("java.home"))); // configure java home - jvm.workingDir(new File(config.getPooledTimeSeriesPath())); // to configure working directory to configure various attributes: + jvm.workingDir(new File(config.getPooledTimeSeriesPath()).getParentFile()); // to configure working directory to configure various attributes: // to configure heap and vmtype jvm.initialHeap(512); // or jvm.initialHeap("512m"); From 1a653226da71852de7b7a1335126d0120736d595 Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Fri, 27 Nov 2015 13:02:24 -0800 Subject: [PATCH 16/19] Fixes discussed on thread. 1. use commons-exec instead of custom exec code. 2. Use table instead of vector. 3. Provide of and og vecSize and frameSize in metadata. 4. add of and og computations. 5. fix XHTML and disable of and og table headings. --- tika-parsers/pom.xml | 7 - .../parser/pot/PooledTimeSeriesParser.java | 395 ++++++++---------- .../pot/PooledTimeSeriesConfig.properties | 18 - 3 files changed, 179 insertions(+), 241 deletions(-) delete mode 100644 tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties diff --git a/tika-parsers/pom.xml b/tika-parsers/pom.xml index 2b78ececc9..600a923dad 100644 --- a/tika-parsers/pom.xml +++ b/tika-parsers/pom.xml @@ -355,13 +355,6 @@ 3.2.2 provided - - - - in.jlibs - jlibs-core - 2.1 - diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 1936441b69..26a0a0d5c1 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -24,249 +24,212 @@ import org.apache.tika.mime.MediaType; import org.apache.tika.parser.AbstractParser; import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.external.ExternalParser; import org.apache.tika.sax.XHTMLContentHandler; -import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; -import java.io.Reader; -import org.apache.commons.io.IOUtils; +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteWatchdog; +import org.apache.commons.exec.PumpStreamHandler; +import org.apache.commons.exec.environment.EnvironmentUtils; +import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.apache.tika.io.TemporaryResources; -import org.apache.tika.io.TikaInputStream; import org.xml.sax.helpers.AttributesImpl; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; -import jlibs.core.lang.JavaProcessBuilder; import static java.nio.charset.StandardCharsets.UTF_8; - public class PooledTimeSeriesParser extends AbstractParser { - private static final PooledTimeSeriesConfig DEFAULT_CONFIG = new PooledTimeSeriesConfig(); - private static final Set SUPPORTED_TYPES = Collections.unmodifiableSet( - new HashSet(Arrays.asList(new MediaType[]{ - MediaType.video("avi"), MediaType.video("mp4") - // TODO: Add all supported video types - }))); - - - // check if opencv is present - private boolean hasOpenCV() { - // TODO - return false; - } - - /** - * Returns the set of media types supported by this parser when used - * with the given parse context. - * - * @param context parse context - * @return immutable set of media types - * @since Apache Tika 0.7 - */ - @Override - public Set getSupportedTypes(ParseContext context) { - - // TODO - // Check PooledTImeSeries configs to see if OpenCV is installed - // if yes, then advertise video mime types - // return SUPPORTED_TYPES; - // else return Collections.empty() - - // FIXME: Resolve above TODO and remove this return statement - return SUPPORTED_TYPES; - } - - /** - * Parses a document stream into a sequence of XHTML SAX events. - * Fills in related document metadata in the given metadata object. - *

- * The given document stream is consumed but not closed by this method. - * The responsibility to close the stream remains on the caller. - *

- * Information about the parsing context can be passed in the context - * parameter. See the parser implementations for the kinds of context - * information they expect. - * - * @param stream the document stream (input) - * @param handler handler for the XHTML SAX events (output) - * @param metadata document metadata (input and output) - * @param context parse context - * @throws IOException if the document stream could not be read - * @throws SAXException if the SAX events could not be processed - * @throws TikaException if the document could not be parsed - * @since Apache Tika 0.5 - */ - @Override - public void parse(InputStream stream, ContentHandler handler, Metadata metadata, ParseContext context) throws IOException, SAXException, TikaException { - - // TODO - // Setup deps/pre-rqs - PooledTimeSeriesConfig config = context.get(PooledTimeSeriesConfig.class, DEFAULT_CONFIG); - - - // TODO: Check for PooledTImeSeries and OpenCV - // if ( !hasOpenCV()) { - // return; - // } - // - XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); - - TemporaryResources tmp = new TemporaryResources(); - File output = null; - try { - TikaInputStream tikaStream = TikaInputStream.get(stream, tmp); - File input = tikaStream.getFile(); - - //long size = tikaStream.getLength(); - - output = tmp.createTemporaryFile(); - - computePoT(input, output, config); - - // Output is same as inputfilename with .of.txt as suffix - // TODO: Repeast for .hog.txt - output = new File(input.getAbsoluteFile() + ".of.txt"); - - doExtract(new FileInputStream(output), xhtml); - - } - finally { - tmp.dispose(); - if (output != null) { - output.delete(); - } - } + private static final long serialVersionUID = -2855917932512164988L; + private static final Set SUPPORTED_TYPES = Collections + .unmodifiableSet(new HashSet(Arrays.asList(new MediaType[] { + MediaType.video("avi"), MediaType.video("mp4") + // TODO: Add all supported video types + }))); + + private static final Log LOG = LogFactory + .getLog(PooledTimeSeriesParser.class); + + public boolean isAvailable() { + return ExternalParser.check( + new String[] { "pooled-time-series", "--help" }, -1); + } + + /** + * Returns the set of media types supported by this parser when used with the + * given parse context. + * + * @param context + * parse context + * @return immutable set of media types + * @since Apache Tika 0.7 + */ + @Override + public Set getSupportedTypes(ParseContext context) { + return SUPPORTED_TYPES; + } + + /** + * Parses a document stream into a sequence of XHTML SAX events. Fills in + * related document metadata in the given metadata object. + *

+ * The given document stream is consumed but not closed by this method. The + * responsibility to close the stream remains on the caller. + *

+ * Information about the parsing context can be passed in the context + * parameter. See the parser implementations for the kinds of context + * information they expect. + * + * @param stream + * the document stream (input) + * @param handler + * handler for the XHTML SAX events (output) + * @param metadata + * document metadata (input and output) + * @param context + * parse context + * @throws IOException + * if the document stream could not be read + * @throws SAXException + * if the SAX events could not be processed + * @throws TikaException + * if the document could not be parsed + * @since Apache Tika 0.5 + */ + @Override + public void parse(InputStream stream, ContentHandler handler, + Metadata metadata, ParseContext context) throws IOException, + SAXException, TikaException { + + if (!isAvailable()) { + LogFactory.getLog(PooledTimeSeriesParser.class).warn( + "PooledTimeSeries not installed!"); + return; } - private void computePoT(File input, File output, PooledTimeSeriesConfig config) throws IOException, TikaException { - JavaProcessBuilder jvm = new JavaProcessBuilder(); - jvm.javaHome(new File(System.getProperty("java.home"))); // configure java home - jvm.workingDir(new File(config.getPooledTimeSeriesPath()).getParentFile()); // to configure working directory to configure various attributes: - - // to configure heap and vmtype - jvm.initialHeap(512); // or jvm.initialHeap("512m"); - jvm.maxHeap(1024); // or jvm.maxHeap("1024m"); - - jvm.jvmArg("-jar"); - jvm.jvmArg(config.getPooledTimeSeriesPath()); - - jvm.libraryPath(config.getOpenCVPath()); - - jvm.jvmArg("-f"); - jvm.jvmArg(input.getPath()); - - - Process process; - try { - String command[] = jvm.command(); - process = jvm.launch(System.out, System.err); - process.waitFor(); - - process.getOutputStream().close(); - InputStream out = process.getInputStream(); - InputStream err = process.getErrorStream(); - - logStream("POT MSG", out, input); - logStream("POT ERROR", err, input); - - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); + + TemporaryResources tmp = new TemporaryResources(); + File output = null; + try { + TikaInputStream tikaStream = TikaInputStream.get(stream, tmp); + File input = tikaStream.getFile(); + String cmdOutput = computePoT(input); + FileInputStream ofStream = new FileInputStream(new File( + input.getAbsoluteFile() + ".of.txt")); + FileInputStream ogStream = new FileInputStream(new File( + input.getAbsoluteFile() + ".hog.txt")); + extractHeaderOutput(ofStream, metadata, "of"); + extractHeaderOutput(ogStream, metadata, "og"); + xhtml.startDocument(); + doExtract(ofStream, xhtml, "Histogram of Optical Flow (HOF)", + metadata.get("of_frames"), metadata.get("of_vecSize")); + doExtract(ogStream, xhtml, "Histogram of Optical Gradients (HOG)", + metadata.get("og_frames"), metadata.get("og_vecSize")); + xhtml.endDocument(); + + } finally { + tmp.dispose(); + if (output != null) { + output.delete(); + } } - - /** - * Starts a thread that reads the contents of the standard output or error - * stream of the given process to not block the process. The stream is closed - * once fully processed. - */ - private void logStream(final String logType, final InputStream stream, final File file) { - new Thread() { - public void run() { - Reader reader = new InputStreamReader(stream, UTF_8); - StringBuilder out = new StringBuilder(); - char[] buffer = new char[1024]; - try { - for (int n = reader.read(buffer); n != -1; n = reader.read(buffer)) - out.append(buffer, 0, n); - } catch (IOException e) { - - } finally { - IOUtils.closeQuietly(stream); - } - - String msg = out.toString(); - LogFactory.getLog(PooledTimeSeriesParser.class).debug(msg); - } - }.start(); + } + + private String computePoT(File input) + throws IOException, TikaException { + + CommandLine cmdLine = new CommandLine("pooled-time-series"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + cmdLine.addArgument("-f"); + cmdLine.addArgument(input.getAbsolutePath()); + LOG.debug("Executing: " + cmdLine); + DefaultExecutor exec = new DefaultExecutor(); + exec.setExitValue(0); + ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); + exec.setWatchdog(watchdog); + PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream); + exec.setStreamHandler(streamHandler); + int exitValue = exec + .execute(cmdLine, EnvironmentUtils.getProcEnvironment()); + return outputStream.toString("UTF-8"); + + } + + /** + * Reads the contents of the given stream and write it to the given XHTML + * content handler. The stream is closed once fully processed. + * + * @param stream + * Stream where is the result of ocr + * @param xhtml + * XHTML content handler + * @param tableTitle + * The name of the matrix/table to display. + * @param frames + * Number of frames read from the video. + * @param vecSize + * Size of the OF or HOG vector. + * @throws SAXException + * if the XHTML SAX events could not be handled + * @throws IOException + * if an input error occurred + */ + private void doExtract(InputStream stream, XHTMLContentHandler xhtml, + String tableTitle, String frames, String vecSize) throws SAXException, + IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream, + UTF_8)); + String line = null; + AttributesImpl attributes = new AttributesImpl(); + attributes.addAttribute("", "", "rows", "CDATA", frames); + attributes.addAttribute("", "", "cols", "CDATA", vecSize); + + xhtml.startElement("h3"); + xhtml.characters(tableTitle); + xhtml.endElement("h3"); + xhtml.startElement("table", attributes); + while ((line = reader.readLine()) != null) { + xhtml.startElement("tr"); + for (String val : line.split(" ")) { + xhtml.startElement("td"); + xhtml.characters(val); + xhtml.endElement("td"); + } + xhtml.endElement("tr"); } - - /** - * Reads the contents of the given stream and write it to the given XHTML - * content handler. The stream is closed once fully processed. - * - * @param stream - * Stream where is the result of ocr - * @param xhtml - * XHTML content handler - * @throws SAXException - * if the XHTML SAX events could not be handled - * @throws IOException - * if an input error occurred - */ - private void doExtract(InputStream stream, XHTMLContentHandler xhtml) throws SAXException, IOException { - - BufferedReader reader = new BufferedReader(new InputStreamReader(stream, UTF_8)); - String line = reader.readLine(); - String[] firstLine = line.split(" "); - String frames = firstLine[0]; - String vecSize = firstLine[1]; - - AttributesImpl attributes = new AttributesImpl(); - attributes.addAttribute("", "", "numRows", "CDATA", frames); - attributes.addAttribute("", "", "numCols", "CDATA", vecSize); - - xhtml.startDocument(); - xhtml.startElement("div", attributes); - - xhtml.startElement("ol"); - while ((line = reader.readLine()) != null) { - xhtml.startElement("ol"); - for (String val : line.split(" ")) { - xhtml.startElement("li"); - xhtml.characters(val); - xhtml.endElement("li"); - } - xhtml.endElement("ol"); - } - xhtml.endElement("ol"); - - xhtml.endDocument(); + xhtml.endElement("table"); + } + + private void extractHeaderOutput(InputStream stream, Metadata metadata, + String prefix) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream, + UTF_8)); + String line = reader.readLine(); + String[] firstLine = line.split(" "); + String frames = firstLine[0]; + String vecSize = firstLine[1]; + + if (prefix == null) { + prefix = ""; } + metadata.add(prefix + "_frames", frames); + metadata.add(prefix + "_vecSize", vecSize); + } } diff --git a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties b/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties deleted file mode 100644 index 294f4503b1..0000000000 --- a/tika-parsers/src/main/resources/org/apache/tika/parser/pot/PooledTimeSeriesConfig.properties +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - -opencvPath=/path/to/opencv/java/ -pooledTimeSeriesPath=/path/to/pooled_time_series.jar -timeout=120 \ No newline at end of file From 3e2d53c3d9f95c9955d92c972c17ff57c6df892c Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Fri, 27 Nov 2015 13:24:15 -0800 Subject: [PATCH 17/19] remove unneeded config. fix HOG name. --- .../parser/pot/PooledTimeSeriesConfig.java | 166 ------------------ .../parser/pot/PooledTimeSeriesParser.java | 4 +- 2 files changed, 2 insertions(+), 168 deletions(-) delete mode 100644 tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java deleted file mode 100644 index 147f6dba5b..0000000000 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesConfig.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.parser.pot; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.Locale; -import java.util.Properties; - -/** - * Configuration for PooledTimeSeriesParser. - * - * This allows to enable PooledTimeSeriesParser and set its parameters: - *

- * PooledTimeSeriesConfig config = new PooledTimeSeriesConfig();
- * config.setOpenCVPath(opencvFolder);
- * parseContext.set(PooledTimeSeriesConfig.class, config);
- *

- * - * Parameters can also be set by either editing the existing PooledTimeSeriesConfig.properties file in, - * tika-parser/src/main/resources/org/apache/tika/parser/pot, or overriding it by creating your own - * and placing it in the package org/apache/tika/parser/pot on the classpath. - * - */ -public class PooledTimeSeriesConfig implements Serializable { - - private static final long serialVersionUID = -4861942486845757891L; - - // Path to OpenCV installation folder, if not on system path. - private String opencvPath = ""; - - // Path to PooledTimeSeries program - private String pooledTimeSeriesPath = ""; - - // Maximum time (seconds) to wait for the pot-ing process termination - private int timeout = 84600; - - /** - * Default contructor. - */ - public PooledTimeSeriesConfig() { - init(this.getClass().getResourceAsStream("PooledTimeSeriesConfig.properties")); - } - - /** - * Loads properties from InputStream and then tries to close InputStream. - * If there is an IOException, this silently swallows the exception - * and goes back to the default. - * - * @param is - */ - public PooledTimeSeriesConfig(InputStream is) { - init(is); - } - - private void init(InputStream is) { - if (is == null) { - return; - } - Properties props = new Properties(); - try { - props.load(is); - } catch (IOException e) { - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - //swallow - } - } - } - - setOpenCVPath( - getProp(props, "opencvPath", getOpenCVPath())); - setPooledTimeSeriesPath( - getProp(props, "pooledTimeSeriesPath", getOpenCVPath())); - setTimeout( - getProp(props, "timeout", getTimeout())); - - } - - /** @see #setOpenCVPath(String tesseractPath)*/ - public String getOpenCVPath() { - return opencvPath; - } - - /** - * Set the path to the OpenCV executable, needed if it is not on system path. - */ - public void setOpenCVPath(String opencvPath) { - if(!opencvPath.isEmpty() && !opencvPath.endsWith(File.separator)) - opencvPath += File.separator; - - this.opencvPath = opencvPath; - } - - public String getPooledTimeSeriesPath() { - return pooledTimeSeriesPath; - } - - public void setPooledTimeSeriesPath(String pooledTimeSeriesPath) { - this.pooledTimeSeriesPath = pooledTimeSeriesPath; - } - - /** - * Set maximum time (seconds) to wait for the pooled time series process to terminate. - * Default value is 120s. - */ - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - /** @see #setTimeout(int timeout)*/ - public int getTimeout() { - return timeout; - } - - /** - * Get property from the properties file passed in. - * @param properties properties file to read from. - * @param property the property to fetch. - * @param defaultMissing default parameter to use. - * @return the value. - */ - private int getProp(Properties properties, String property, int defaultMissing) { - String p = properties.getProperty(property); - if (p == null || p.isEmpty()){ - return defaultMissing; - } - try { - return Integer.parseInt(p); - } catch (Throwable ex) { - throw new RuntimeException(String.format(Locale.ROOT, "Cannot parse PooledTimeSeriesConfig variable %s, invalid integer value", - property), ex); - } - } - - /** - * Get property from the properties file passed in. - * @param properties properties file to read from. - * @param property the property to fetch. - * @param defaultMissing default parameter to use. - * @return the value. - */ - private String getProp(Properties properties, String property, String defaultMissing) { - return properties.getProperty(property, defaultMissing); - } -} diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index 26a0a0d5c1..df61699569 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -137,9 +137,9 @@ public void parse(InputStream stream, ContentHandler handler, extractHeaderOutput(ofStream, metadata, "of"); extractHeaderOutput(ogStream, metadata, "og"); xhtml.startDocument(); - doExtract(ofStream, xhtml, "Histogram of Optical Flow (HOF)", + doExtract(ofStream, xhtml, "Histogram of Optical Flows (HOF)", metadata.get("of_frames"), metadata.get("of_vecSize")); - doExtract(ogStream, xhtml, "Histogram of Optical Gradients (HOG)", + doExtract(ogStream, xhtml, "Histogram of Oriented Gradients (HOG)", metadata.get("og_frames"), metadata.get("og_vecSize")); xhtml.endDocument(); From fe43ea3e63015cdad2ec4f437858fec006cc122d Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Fri, 27 Nov 2015 13:25:32 -0800 Subject: [PATCH 18/19] no dep on jlibs anymore. --- tika-bundle/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/tika-bundle/pom.xml b/tika-bundle/pom.xml index 438beb0554..d0968a66e0 100644 --- a/tika-bundle/pom.xml +++ b/tika-bundle/pom.xml @@ -186,7 +186,6 @@ javax.xml.stream.events;version="[1.0,2)";resolution:=optional, javax.xml.stream.util;version="[1.0,2)";resolution:=optional, javax.ws.rs.core;resolution:=optional, - jlibs.core.lang;resolution:=optional, net.sf.ehcache;resolution:=optional, nu.xom;resolution:=optional, opendap.dap.http;resolution:=optional, From 122306e2c95dadb2cdc9c41f984619bc9e223c33 Mon Sep 17 00:00:00 2001 From: Chris Mattmann Date: Fri, 27 Nov 2015 14:35:10 -0800 Subject: [PATCH 19/19] Fixes to logging code - switch to java.util.logging. --- .../tika/parser/pot/PooledTimeSeriesParser.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java index df61699569..4b6e14c79f 100644 --- a/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java +++ b/tika-parsers/src/main/java/org/apache/tika/parser/pot/PooledTimeSeriesParser.java @@ -36,14 +36,12 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; - +import java.util.logging.Logger; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteWatchdog; import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.exec.environment.EnvironmentUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.xml.sax.helpers.AttributesImpl; import java.util.Arrays; @@ -62,8 +60,7 @@ public class PooledTimeSeriesParser extends AbstractParser { // TODO: Add all supported video types }))); - private static final Log LOG = LogFactory - .getLog(PooledTimeSeriesParser.class); + private static final Logger LOG = Logger.getLogger(PooledTimeSeriesParser.class.getName()); public boolean isAvailable() { return ExternalParser.check( @@ -117,7 +114,7 @@ public void parse(InputStream stream, ContentHandler handler, SAXException, TikaException { if (!isAvailable()) { - LogFactory.getLog(PooledTimeSeriesParser.class).warn( + LOG.warning( "PooledTimeSeries not installed!"); return; } @@ -158,7 +155,7 @@ private String computePoT(File input) ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); cmdLine.addArgument("-f"); cmdLine.addArgument(input.getAbsolutePath()); - LOG.debug("Executing: " + cmdLine); + LOG.fine("Executing: " + cmdLine); DefaultExecutor exec = new DefaultExecutor(); exec.setExitValue(0); ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);