From bdf30117c1b86d044f41d352e411a6d23eaf1c65 Mon Sep 17 00:00:00 2001 From: theli Date: Tue, 29 Nov 2005 07:27:58 +0000 Subject: [PATCH] *) Redesign of parser configuration - restructuring of mimeTypes based on the parsers - displaying parser usage count - displaying human readably parser names - displaying parser version information *) httpdFileHandler.java - adding possibility to support "streaming" servlets which are special servlets that can communicate with the client via the connection streams autonomous - the name of these new servlet types must end with the file extension .stream - this feature will be needed by the yacy ScreenSaver class to fetch statistic data from the peer without the need to reconnect to the server all the time *) Adding human readable names and version information for all supported parsers *) plasmaParser.java - adding new structure to store parser statistic data *) Adding openDocument parser - can be used to parse odt files *) jmimemagic - adding rules to detect openDocument formats properly *) serverLog.java - adding functions that can be used to query if a given logging level is enabled or not. git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@1140 6c8d7289-2bf4-0310-a012-ef5d649a1542 --- htroot/Settings_Parser.inc | 21 +- htroot/Settings_p.java | 48 ++- httpd.mime | 2 + libx/jmimemagic-0.0.4a.jar | Bin 55433 -> 55644 bytes libx/odf_utils_05_11_10.jar | Bin 0 -> 97405 bytes source/de/anomic/http/httpdFileHandler.java | 25 +- .../anomic/plasma/parser/AbstractParser.java | 24 ++ source/de/anomic/plasma/parser/Parser.java | 13 + .../de/anomic/plasma/parser/ParserInfo.java | 34 +++ .../anomic/plasma/parser/bzip/bzipParser.java | 4 +- .../anomic/plasma/parser/doc/docParser.java | 1 + .../anomic/plasma/parser/gzip/gzipParser.java | 1 + .../parser/mimeType/mimeTypeParser.java | 56 +++- source/de/anomic/plasma/parser/odt/build.xml | 55 ++++ .../anomic/plasma/parser/odt/odtParser.java | 214 ++++++++++++++ .../anomic/plasma/parser/pdf/pdfParser.java | 3 +- .../anomic/plasma/parser/rss/rssParser.java | 3 +- .../anomic/plasma/parser/rtf/rtfParser.java | 3 +- .../anomic/plasma/parser/tar/tarParser.java | 58 +++- .../anomic/plasma/parser/vcf/vcfParser.java | 3 +- .../anomic/plasma/parser/zip/zipParser.java | 3 +- source/de/anomic/plasma/plasmaParser.java | 278 +++++++++++------- .../de/anomic/plasma/plasmaSnippetCache.java | 3 +- .../de/anomic/server/logging/serverLog.java | 49 ++- 24 files changed, 735 insertions(+), 166 deletions(-) create mode 100644 libx/odf_utils_05_11_10.jar create mode 100644 source/de/anomic/plasma/parser/ParserInfo.java create mode 100644 source/de/anomic/plasma/parser/odt/build.xml create mode 100644 source/de/anomic/plasma/parser/odt/odtParser.java diff --git a/htroot/Settings_Parser.inc b/htroot/Settings_Parser.inc index 5b2a38a62..2953b68cd 100644 --- a/htroot/Settings_Parser.inc +++ b/htroot/Settings_Parser.inc @@ -7,23 +7,30 @@ For a detailed description of the various MIME-types take a look at Activate Mime-Type -Parser Class Name +Parser Usage #{parser}# - - #[mime]# - #[shortname]# + #[name]# V#[version]# + #[usage]# +   + +#{mime}# + + + #[mimetype]# +   - + +#{/mime}# #{/parser}# - + Enable all parsers   - +  Changes take effect immediately diff --git a/htroot/Settings_p.java b/htroot/Settings_p.java index 1ed1b2643..af3735ee5 100644 --- a/htroot/Settings_p.java +++ b/htroot/Settings_p.java @@ -45,13 +45,16 @@ import java.util.Arrays; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import de.anomic.http.httpHeader; import de.anomic.plasma.plasmaSwitchboard; +import de.anomic.plasma.parser.ParserInfo; import de.anomic.server.serverObjects; import de.anomic.server.serverSwitch; import de.anomic.yacy.yacyCore; @@ -249,29 +252,42 @@ public final class Settings_p { * Parser Configuration */ plasmaSwitchboard sb = (plasmaSwitchboard)env; - Hashtable enabledParsers = sb.parser.getEnabledParserList(); - Hashtable availableParsers = sb.parser.getAvailableParserList(); + HashSet enabledParsers = sb.parser.getEnabledParserList(); + HashSet parserInfos = new HashSet(sb.parser.getAvailableParserList().values()); - // fetching a list of all available mimetypes - List availableParserKeys = Arrays.asList(availableParsers.keySet().toArray(new String[availableParsers.size()])); - - // sort it - Collections.sort(availableParserKeys); +// // fetching a list of all available mimetypes +// List availableParserKeys = Arrays.asList(availableParsers.entrySet().toArray(new ParserInfo[availableParsers.size()])); +// +// // sort it +// Collections.sort(availableParserKeys); // loop through the mimeTypes and add it to the properties boolean allParsersEnabled = true; int parserIdx = 0; - Iterator availableParserIter = availableParserKeys.iterator(); + + Iterator availableParserIter = parserInfos.iterator(); while (availableParserIter.hasNext()) { - String mimeType = (String) availableParserIter.next(); - String parserName = (String) availableParsers.get(mimeType); - boolean parserIsEnabled = enabledParsers.containsKey(mimeType); + ParserInfo parserInfo = (ParserInfo) availableParserIter.next(); + prop.put("parser_" + parserIdx + "_name", parserInfo.parserName); + prop.put("parser_" + parserIdx + "_version", parserInfo.parserVersionNr); + prop.put("parser_" + parserIdx + "_usage", Integer.toString(parserInfo.usageCount)); - prop.put("parser_" + parserIdx + "_mime", mimeType); - prop.put("parser_" + parserIdx + "_name", parserName); - prop.put("parser_" + parserIdx + "_shortname", parserName.substring(parserName.lastIndexOf(".")+1)); - prop.put("parser_" + parserIdx + "_status", parserIsEnabled ? 1:0); - allParsersEnabled &= parserIsEnabled; + int mimeIdx = 0; + Enumeration mimeTypeIter = parserInfo.supportedMimeTypes.keys(); + while (mimeTypeIter.hasMoreElements()) { + String mimeType = (String)mimeTypeIter.nextElement(); + + boolean parserIsEnabled = enabledParsers.contains(mimeType); + + prop.put("parser_" + parserIdx + "_mime_" + mimeIdx + "_mimetype", mimeType); + //prop.put("parser_" + parserIdx + "_name", parserName); + //prop.put("parser_" + parserIdx + "_shortname", parserName.substring(parserName.lastIndexOf(".")+1)); + prop.put("parser_" + parserIdx + "_mime_" + mimeIdx + "_status", enabledParsers.contains(mimeType) ? 1:0); + allParsersEnabled &= parserIsEnabled; + + mimeIdx++; + } + prop.put("parser_" + parserIdx + "_mime", mimeIdx); parserIdx++; } diff --git a/httpd.mime b/httpd.mime index 1327ce1d5..157655749 100644 --- a/httpd.mime +++ b/httpd.mime @@ -37,6 +37,7 @@ mov = video/quicktime mpe = video/mpeg mpeg = video/mpeg mpg = video/mpeg +odt = application/vnd.oasis.opendocument.text ogg = audio/ogg-vorbis pac = application/x-ns-proxy-autoconfig pdf = application/pdf @@ -70,6 +71,7 @@ tif = image/tiff tiff = image/tiff torrent = application/x-bittorrent txt = text/plain +vcf = text/x-vcard wav = audio/x-wav xhtml = application/xhtml+xml xla = application/msexcel diff --git a/libx/jmimemagic-0.0.4a.jar b/libx/jmimemagic-0.0.4a.jar index b3cbfea229ed866c41cef7b6728f1455e945f8d4..66d420782f8bb0363d6d2056efcf8431b61ae11e 100644 GIT binary patch delta 8314 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 E0J@(;4FCWD delta 8076 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 a*ggW0%#;1tIRci=lQ`KP1`5&u00002>&UwR diff --git a/libx/odf_utils_05_11_10.jar b/libx/odf_utils_05_11_10.jar new file mode 100644 index 0000000000000000000000000000000000000000..4e7a174f3d3c8f585fd8d7dfc435c77a2d3e8784 GIT binary patch literal 97405 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 a2e^6jXwG3PZ0{st>Uaryr literal 0 HcmV?d00001 diff --git a/source/de/anomic/http/httpdFileHandler.java b/source/de/anomic/http/httpdFileHandler.java index 5860a3da1..3eeb80df4 100644 --- a/source/de/anomic/http/httpdFileHandler.java +++ b/source/de/anomic/http/httpdFileHandler.java @@ -346,7 +346,7 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http int argc; if (argsString == null) { // no args here, maybe a POST with multipart extension - int length; + int length = 0; //System.out.println("HEADER: " + requestHeader.toString()); // DEBUG if (method.equals(httpHeader.METHOD_POST)) { @@ -356,10 +356,11 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http } else if (requestHeader.gzip()) { length = -1; gzipBody = new GZIPInputStream(body); - } else { - httpd.sendRespondError(conProp,out,4,403,null,"bad post values",null); - return; } +// } else { +// httpd.sendRespondError(conProp,out,4,403,null,"bad post values",null); +// return; +// } // if its a POST, it can be either multipart or as args in the body if ((requestHeader.containsKey(httpHeader.CONTENT_TYPE)) && @@ -438,7 +439,7 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http } }else{ //you cannot share a .png/.gif file with a name like a class in htroot. - if ( !(targetFile.exists()) && !((path.endsWith("png")||path.endsWith("gif"))&&targetClass!=null ) ){ + if ( !(targetFile.exists()) && !((path.endsWith("png")||path.endsWith("gif")||path.endsWith(".stream"))&&targetClass!=null ) ){ targetFile = new File(htDocsPath, path); targetClass = rewriteClassFile(new File(htDocsPath, path)); } @@ -486,6 +487,20 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http Thread.currentThread().sleep(200); // see below serverFileUtils.write(result, out); } + } else if ((targetClass != null) && (path.endsWith(".stream"))) { + // call rewrite-class + requestHeader.put("CLIENTIP", conProp.getProperty("CLIENTIP")); + requestHeader.put("PATH", path); + requestHeader.put("INPUTSTREAM", body); + requestHeader.put("OUTPUTSTREAM", out); + + httpd.sendRespondHeader(this.connectionProperties, out, httpVersion, 200, null); + + // in case that there are no args given, args = null or empty hashmap + serverObjects tp = (serverObjects) rewriteMethod(targetClass).invoke(null, new Object[] {requestHeader, args, switchboard}); + + this.forceConnectionClose(); + return; } else if ((targetFile.exists()) && (targetFile.canRead())) { // we have found a file that can be written to the client // if this file uses templates, then we use the template diff --git a/source/de/anomic/plasma/parser/AbstractParser.java b/source/de/anomic/plasma/parser/AbstractParser.java index f7ed3ab35..e7defd382 100644 --- a/source/de/anomic/plasma/parser/AbstractParser.java +++ b/source/de/anomic/plasma/parser/AbstractParser.java @@ -73,6 +73,16 @@ public abstract class AbstractParser implements Parser{ * purposes. */ protected serverLog theLogger = null; + + /** + * Version number of the parser + */ + protected String parserVersionNr = "0.1"; + + /** + * Parser name + */ + protected String parserName = this.getClass().getSimpleName(); /** * The Constructor of this class. @@ -165,4 +175,18 @@ public abstract class AbstractParser implements Parser{ this.theLogger = log; } + /** + * Returns the version number of the parser + * @return parser version number + */ + public String getVersion() { + return this.parserVersionNr; + } + + /** + * Return the name of the parser + */ + public String getName() { + return parserName; + } } diff --git a/source/de/anomic/plasma/parser/Parser.java b/source/de/anomic/plasma/parser/Parser.java index 038b88505..dd3875d2a 100644 --- a/source/de/anomic/plasma/parser/Parser.java +++ b/source/de/anomic/plasma/parser/Parser.java @@ -122,4 +122,17 @@ public interface Parser { */ public void setLogger(serverLog log); + /** + * Returns the version number of the current parser + * @return parser version number + */ + public String getVersion(); + + /** + * Returns the name of the parser + * @return parser name + */ + public String getName(); } + + diff --git a/source/de/anomic/plasma/parser/ParserInfo.java b/source/de/anomic/plasma/parser/ParserInfo.java new file mode 100644 index 000000000..a7e68663a --- /dev/null +++ b/source/de/anomic/plasma/parser/ParserInfo.java @@ -0,0 +1,34 @@ +package de.anomic.plasma.parser; + +import java.util.Hashtable; + +public class ParserInfo { + // general parser info + public Class parserClass; + public String parserClassName; + + public String parserName; + public String parserVersionNr; + + // parser properties + public String[] libxDependencies; + public Hashtable supportedMimeTypes; + + // usage statistic + public int usageCount = 0; + + public String toString() { + StringBuffer toStr = new StringBuffer(); + + toStr.append(this.parserName).append(" V") + .append((this.parserVersionNr==null)?"0.0":this.parserVersionNr).append(" | ") + .append(this.parserClassName).append(" | ") + .append(this.supportedMimeTypes); + + return toStr.toString(); + } + + public synchronized void incUsageCounter() { + this.usageCount++; + } +} diff --git a/source/de/anomic/plasma/parser/bzip/bzipParser.java b/source/de/anomic/plasma/parser/bzip/bzipParser.java index e9e378b81..887932f5e 100644 --- a/source/de/anomic/plasma/parser/bzip/bzipParser.java +++ b/source/de/anomic/plasma/parser/bzip/bzipParser.java @@ -77,9 +77,10 @@ public class bzipParser extends AbstractParser implements Parser { private static final String[] LIBX_DEPENDENCIES = new String[] { "bzip2.jar" }; - + public bzipParser() { super(LIBX_DEPENDENCIES); + parserName = "Bzip 2 UNIX Compressed File Parser"; } public Hashtable getSupportedMimeTypes() { @@ -105,7 +106,6 @@ public class bzipParser extends AbstractParser implements Parser { int read = 0; byte[] data = new byte[1024]; - CBZip2InputStream zippedContent = new CBZip2InputStream(source); tempFile = File.createTempFile("bunzip","tmp"); diff --git a/source/de/anomic/plasma/parser/doc/docParser.java b/source/de/anomic/plasma/parser/doc/docParser.java index 0ed57ad5f..c339ad006 100644 --- a/source/de/anomic/plasma/parser/doc/docParser.java +++ b/source/de/anomic/plasma/parser/doc/docParser.java @@ -75,6 +75,7 @@ implements Parser { public docParser() { super(LIBX_DEPENDENCIES); + parserName = "Word Document Parser"; } public plasmaParserDocument parse(URL location, String mimeType, diff --git a/source/de/anomic/plasma/parser/gzip/gzipParser.java b/source/de/anomic/plasma/parser/gzip/gzipParser.java index f33993f1f..c3028d561 100644 --- a/source/de/anomic/plasma/parser/gzip/gzipParser.java +++ b/source/de/anomic/plasma/parser/gzip/gzipParser.java @@ -76,6 +76,7 @@ public class gzipParser extends AbstractParser implements Parser { public gzipParser() { super(LIBX_DEPENDENCIES); + parserName = "GNU Zip Compressed Archive Parser"; } public Hashtable getSupportedMimeTypes() { diff --git a/source/de/anomic/plasma/parser/mimeType/mimeTypeParser.java b/source/de/anomic/plasma/parser/mimeType/mimeTypeParser.java index 910ac7f3c..6f2f73454 100644 --- a/source/de/anomic/plasma/parser/mimeType/mimeTypeParser.java +++ b/source/de/anomic/plasma/parser/mimeType/mimeTypeParser.java @@ -47,6 +47,7 @@ import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.Collection; +import java.util.HashMap; import java.util.Hashtable; import org.apache.log4j.Level; @@ -74,7 +75,10 @@ implements Parser { static { SUPPORTED_MIME_TYPES.put("text/xml","xml"); SUPPORTED_MIME_TYPES.put("application/xml","xml"); - SUPPORTED_MIME_TYPES.put("application/octet-stream",""); + SUPPORTED_MIME_TYPES.put("application/x-xml","xml"); + SUPPORTED_MIME_TYPES.put("application/octet-stream",""); + SUPPORTED_MIME_TYPES.put("application/x-compress",""); + SUPPORTED_MIME_TYPES.put("application/x-compressed",""); } /** @@ -88,14 +92,56 @@ implements Parser { "xerces.jar" }; + /** + * Helping structure used to detect loops in the mimeType detection + * process + */ + private static Hashtable threadLoopDetection = new Hashtable(); + public mimeTypeParser() { super(LIBX_DEPENDENCIES); + parserName = "MimeType Parser"; + } + + public String getMimeType (File sourceFile) { + String mimeType = null; + + try { + Magic theMagic = new Magic(); + MagicMatch match = theMagic.getMagicMatch(sourceFile); + + // if a match was found we can return the new mimeType + if (match!=null) { + Collection subMatches = match.getSubMatches(); + if ((subMatches != null) && (!subMatches.isEmpty())) { + mimeType = ((MagicMatch) subMatches.iterator().next()).getMimeType(); + } else { + mimeType = match.getMimeType(); + } + return mimeType; + } + } catch (Exception e) { + + } + return null; } public plasmaParserDocument parse(URL location, String mimeType, File sourceFile) throws ParserException { + String orgMimeType = mimeType; + // determining the mime type of the file ... try { + // adding current thread to loop detection list + Integer loopDepth = null; + if (threadLoopDetection.containsKey(Thread.currentThread())) { + loopDepth = (Integer) threadLoopDetection.get(Thread.currentThread()); + } else { + loopDepth = new Integer(0); + } + if (loopDepth.intValue() > 5) return null; + threadLoopDetection.put(Thread.currentThread(),new Integer(loopDepth.intValue()+1)); + // deactivating the logging for jMimeMagic Logger theLogger = Logger.getLogger("net.sf.jmimemagic"); theLogger.setLevel(Level.OFF); @@ -115,6 +161,7 @@ implements Parser { // to avoid loops we have to test if the mimetype has changed ... if (this.getSupportedMimeTypes().containsKey(mimeType)) return null; + if (orgMimeType.equals(mimeType)) return null; plasmaParser theParser = new plasmaParser(); return theParser.parseSource(location,mimeType,sourceFile); @@ -123,6 +170,13 @@ implements Parser { } catch (Exception e) { return null; + } finally { + Integer loopDepth = (Integer) threadLoopDetection.get(Thread.currentThread()); + if (loopDepth.intValue() <= 1) { + threadLoopDetection.remove(Thread.currentThread()); + } else { + threadLoopDetection.put(Thread.currentThread(), new Integer(loopDepth.intValue()-1)); + } } } diff --git a/source/de/anomic/plasma/parser/odt/build.xml b/source/de/anomic/plasma/parser/odt/build.xml new file mode 100644 index 000000000..25ae3e5d5 --- /dev/null +++ b/source/de/anomic/plasma/parser/odt/build.xml @@ -0,0 +1,55 @@ + + + + A class to parse gzip files + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/de/anomic/plasma/parser/odt/odtParser.java b/source/de/anomic/plasma/parser/odt/odtParser.java new file mode 100644 index 000000000..3b9708472 --- /dev/null +++ b/source/de/anomic/plasma/parser/odt/odtParser.java @@ -0,0 +1,214 @@ +//zipParser.java +//------------------------ +//part of YaCy +//(C) by Michael Peter Christen; mc@anomic.de +//first published on http://www.anomic.de +//Frankfurt, Germany, 2005 +// +//this file is contributed by Martin Thelian +//last major change: 16.05.2005 +// +//This program is free software; you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation; either version 2 of the License, or +//(at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//Using this software in any meaning (reading, learning, copying, compiling, +//running) means that you agree that the Author(s) is (are) not responsible +//for cost, loss of data or any harm that may be caused directly or indirectly +//by usage of this softare or this documentation. The usage of this software +//is on your own risk. The installation and usage (starting/running) of this +//software may allow other people or application to access your computer and +//any attached devices and is highly dependent on the configuration of the +//software which must be done by the user of the software; the author(s) is +//(are) also not responsible for proper configuration and usage of the +//software, even if provoked by documentation provided together with +//the software. +// +//Any changes to this file according to the GPL as documented in the file +//gpl.txt aside this file in the shipment you received can be done to the +//lines that follows this copyright notice here, but changes must not be +//done inside the copyright notive above. A re-distribution must contain +//the intact and unchanged copyright notice. +//Contributions and changes to the program code must be marked as such. + +package de.anomic.plasma.parser.odt; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import com.catcode.odf.ODFMetaFileAnalyzer; +import com.catcode.odf.OpenDocumentMetadata; +import com.catcode.odf.OpenDocumentTextInputStream; + +import de.anomic.http.httpc; +import de.anomic.plasma.plasmaParserDocument; +import de.anomic.plasma.parser.AbstractParser; +import de.anomic.plasma.parser.Parser; +import de.anomic.plasma.parser.ParserException; +import de.anomic.server.serverFileUtils; +import de.anomic.server.logging.serverLog; + +public class odtParser extends AbstractParser implements Parser { + + /** + * a list of mime types that are supported by this parser class + * @see #getSupportedMimeTypes() + */ + public static final Hashtable SUPPORTED_MIME_TYPES = new Hashtable(); + static { + SUPPORTED_MIME_TYPES.put("application/vnd.oasis.opendocument.text","odt"); + SUPPORTED_MIME_TYPES.put("application/x-vnd.oasis.opendocument.text","odt"); + } + + /** + * a list of library names that are needed by this parser + * @see Parser#getLibxDependences() + */ + private static final String[] LIBX_DEPENDENCIES = new String[] {"odf_utils_05_11_10.jar"}; + + public odtParser() { + super(LIBX_DEPENDENCIES); + parserName = "OASIS OpenDocument V2 Text Document Parser"; + } + + public Hashtable getSupportedMimeTypes() { + return SUPPORTED_MIME_TYPES; + } + + public plasmaParserDocument parse(URL location, String mimeType, File dest) throws ParserException { + + try { + byte[] docContent = null; + String docDescription = null; + String docKeywords = null; + String docShortTitle = null; + String docLongTitle = null; + + // opening the file as zip file + ZipFile zipFile= new ZipFile(dest); + Enumeration zipEnum = zipFile.entries(); + + // looping through all containing files + while (zipEnum.hasMoreElements()) { + ZipEntry zipEntry= (ZipEntry) zipEnum.nextElement(); + String entryName = zipEntry.getName(); + + // content.xml contains the document content in xml format + if (entryName.equals("content.xml")) { + InputStream zipFileEntryStream = zipFile.getInputStream(zipEntry); + OpenDocumentTextInputStream odStream = new OpenDocumentTextInputStream(zipFileEntryStream); + docContent = serverFileUtils.read(odStream); + + // meta.xml contains metadata about the document + } else if (entryName.equals("meta.xml")) { + InputStream zipFileEntryStream = zipFile.getInputStream(zipEntry); + ODFMetaFileAnalyzer metaAnalyzer = new ODFMetaFileAnalyzer(); + OpenDocumentMetadata metaData = metaAnalyzer.analyzeMetaData(zipFileEntryStream); + docDescription = metaData.getDescription(); + docKeywords = metaData.getKeyword(); + docShortTitle = metaData.getTitle(); + docLongTitle = metaData.getSubject(); + + // if there is no title availabe we generate one + if (docLongTitle == null) { + if (docShortTitle != null) { + docLongTitle = docShortTitle; + } else if (docContent.length <= 80) { + docLongTitle = new String(docContent); + } else { + byte[] title = new byte[80]; + System.arraycopy(docContent, 0, title, 0, 80); + docLongTitle = new String(title); + } + docLongTitle. + replaceAll("\r\n"," "). + replaceAll("\n"," "). + replaceAll("\r"," "). + replaceAll("\t"," "); + } + } + } + + return new plasmaParserDocument( + location, + mimeType, + docKeywords, + docShortTitle, + docLongTitle, + null, + docDescription, + docContent, + null, + null); + } catch (Exception e) { + e.printStackTrace(); + throw new ParserException("Unable to parse the odt content. " + e.getMessage()); + } catch (Error e) { + throw new ParserException("Unable to parse the odt content. " + e.getMessage()); + } + } + + public plasmaParserDocument parse(URL location, String mimeType, InputStream source) throws ParserException { + File dest = null; + try { + // creating a tempfile + dest = File.createTempFile("OpenDocument", ".odt"); + dest.deleteOnExit(); + + // copying the stream into a file + serverFileUtils.copy(source, dest); + + // parsing the content + return parse(location, mimeType, dest); + } catch (Exception e) { + throw new ParserException("Unable to parse the odt document. " + e.getMessage()); + } finally { + if (dest != null) try { dest.delete(); } catch (Exception e){} + } + } + + public void reset() { + // Nothing todo here at the moment + + } + + public static void main(String[] args) { + try { + if (args.length != 1) return; + + // getting the content URL + URL contentUrl = new URL(args[0]); + + // creating a new parser + odtParser testParser = new odtParser(); + + // setting the parser logger + testParser.setLogger(new serverLog("PARSER.ODT")); + + // downloading the document content + byte[] content = httpc.singleGET(contentUrl, 10000, null, null, null); + ByteArrayInputStream input = new ByteArrayInputStream(content); + + // parsing the document + testParser.parse(contentUrl, "application/vnd.oasis.opendocument.text", input); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/source/de/anomic/plasma/parser/pdf/pdfParser.java b/source/de/anomic/plasma/parser/pdf/pdfParser.java index 70db05b45..706d41413 100644 --- a/source/de/anomic/plasma/parser/pdf/pdfParser.java +++ b/source/de/anomic/plasma/parser/pdf/pdfParser.java @@ -74,10 +74,11 @@ public class pdfParser extends AbstractParser implements Parser { */ private static final String[] LIBX_DEPENDENCIES = new String[] { "PDFBox-0.7.2.jar" - }; + }; public pdfParser() { super(LIBX_DEPENDENCIES); + parserName = "Acrobat Portable Document Parser"; } public Hashtable getSupportedMimeTypes() { diff --git a/source/de/anomic/plasma/parser/rss/rssParser.java b/source/de/anomic/plasma/parser/rss/rssParser.java index dd2d8121c..1197cafa8 100644 --- a/source/de/anomic/plasma/parser/rss/rssParser.java +++ b/source/de/anomic/plasma/parser/rss/rssParser.java @@ -91,10 +91,11 @@ public class rssParser extends AbstractParser implements Parser { "informa-0.6.0.jar", "commons-logging.jar", "jdom.jar" - }; + }; public rssParser() { super(LIBX_DEPENDENCIES); + parserName = "Rich Site Summary/Atom Feed Parser"; } public plasmaParserDocument parse(URL location, String mimeType, diff --git a/source/de/anomic/plasma/parser/rtf/rtfParser.java b/source/de/anomic/plasma/parser/rtf/rtfParser.java index 329605cce..667fc5285 100644 --- a/source/de/anomic/plasma/parser/rtf/rtfParser.java +++ b/source/de/anomic/plasma/parser/rtf/rtfParser.java @@ -73,10 +73,11 @@ implements Parser { * a list of library names that are needed by this parser * @see Parser#getLibxDependences() */ - private static final String[] LIBX_DEPENDENCIES = new String[] {}; + private static final String[] LIBX_DEPENDENCIES = new String[] {}; public rtfParser() { super(LIBX_DEPENDENCIES); + parserName = "Rich Text Format Parser"; } public plasmaParserDocument parse(URL location, String mimeType, diff --git a/source/de/anomic/plasma/parser/tar/tarParser.java b/source/de/anomic/plasma/parser/tar/tarParser.java index 71dafb99f..10d512425 100644 --- a/source/de/anomic/plasma/parser/tar/tarParser.java +++ b/source/de/anomic/plasma/parser/tar/tarParser.java @@ -44,13 +44,16 @@ package de.anomic.plasma.parser.tar; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.InputStream; +import java.io.PushbackInputStream; import java.net.URL; import java.util.Arrays; import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedList; import java.util.Map; +import java.util.zip.GZIPInputStream; import com.ice.tar.TarEntry; import com.ice.tar.TarInputStream; @@ -61,6 +64,7 @@ import de.anomic.plasma.parser.AbstractParser; import de.anomic.plasma.parser.Parser; import de.anomic.plasma.parser.ParserException; import de.anomic.server.serverByteBuffer; +import de.anomic.server.serverFileUtils; public class tarParser extends AbstractParser implements Parser { @@ -71,6 +75,7 @@ public class tarParser extends AbstractParser implements Parser { public static final Hashtable SUPPORTED_MIME_TYPES = new Hashtable(); static { SUPPORTED_MIME_TYPES.put("application/x-tar","tar"); + SUPPORTED_MIME_TYPES.put("application/tar","tar"); } /** @@ -83,6 +88,7 @@ public class tarParser extends AbstractParser implements Parser { public tarParser() { super(LIBX_DEPENDENCIES); + parserName = "Tape Archive File Parser"; } public Hashtable getSupportedMimeTypes() { @@ -92,6 +98,18 @@ public class tarParser extends AbstractParser implements Parser { public plasmaParserDocument parse(URL location, String mimeType, InputStream source) throws ParserException { try { + // creating a new parser class to parse the unzipped content + plasmaParser theParser = new plasmaParser(); + + /* + * If the mimeType was not reported correcly by the webserve we + * have to decompress it first + */ + String ext = plasmaParser.getFileExt(location).toLowerCase(); + if (ext.equals("gz") || ext.equals("tgz")) { + source = new GZIPInputStream(source); + } + StringBuffer docKeywords = new StringBuffer(); StringBuffer docShortTitle = new StringBuffer(); StringBuffer docLongTitle = new StringBuffer(); @@ -100,11 +118,7 @@ public class tarParser extends AbstractParser implements Parser { serverByteBuffer docText = new serverByteBuffer(); Map docAnchors = new HashMap(); Map docImages = new HashMap(); - - - // creating a new parser class to parse the unzipped content - plasmaParser theParser = new plasmaParser(); - + // looping through the contained files TarEntry entry; TarInputStream tin = new TarInputStream(source); @@ -113,22 +127,34 @@ public class tarParser extends AbstractParser implements Parser { if (entry.isDirectory()) continue; // Get the entry name - String entryName = entry.getName(); - int idx = entryName.lastIndexOf("."); - String entryExt = (idx > -1) ? entryName.substring(idx+1) : null; + int idx = -1; + String entryName = entry.getName(); + idx = entryName.lastIndexOf("/"); + if (idx != -1) entryName = entryName.substring(idx+1); + idx = entryName.lastIndexOf("."); + String entryExt = (idx > -1) ? entryName.substring(idx+1) : ""; // trying to determine the mimeType per file extension String entryMime = plasmaParser.getMimeTypeByFileExt(entryExt); // getting the entry content - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[(int) entry.getSize()]; - int bytesRead = tin.read(buf); - bos.write(buf); - byte[] ut = bos.toByteArray(); - - // parsing the content - plasmaParserDocument theDoc = theParser.parseSource(location,entryMime,ut); + plasmaParserDocument theDoc = null; + File tempFile = null; + try { + + + byte[] buf = new byte[(int) entry.getSize()]; + int bytesRead = tin.read(buf); + + tempFile = File.createTempFile("tarParser_" + ((idx>-1)?entryName.substring(0,idx):entryName), (entryExt.length()>0)?"."+entryExt:entryExt); + serverFileUtils.write(buf, tempFile); + + // parsing the content + + theDoc = theParser.parseSource(tempFile.toURL(),entryMime,tempFile); + } finally { + if (tempFile != null) try {tempFile.delete(); } catch(Exception ex){} + } if (theDoc == null) continue; // merging all documents together diff --git a/source/de/anomic/plasma/parser/vcf/vcfParser.java b/source/de/anomic/plasma/parser/vcf/vcfParser.java index 0e1fe5b61..c46771f67 100644 --- a/source/de/anomic/plasma/parser/vcf/vcfParser.java +++ b/source/de/anomic/plasma/parser/vcf/vcfParser.java @@ -86,10 +86,11 @@ public class vcfParser extends AbstractParser implements Parser { * a list of library names that are needed by this parser * @see Parser#getLibxDependences() */ - private static final String[] LIBX_DEPENDENCIES = new String[] {"commons-codec-1.3.jar"}; + private static final String[] LIBX_DEPENDENCIES = new String[] {"commons-codec-1.3.jar"}; public vcfParser() { super(LIBX_DEPENDENCIES); + parserName = "vCard Parser"; } public Hashtable getSupportedMimeTypes() { diff --git a/source/de/anomic/plasma/parser/zip/zipParser.java b/source/de/anomic/plasma/parser/zip/zipParser.java index fa5cd2388..6372eec0d 100644 --- a/source/de/anomic/plasma/parser/zip/zipParser.java +++ b/source/de/anomic/plasma/parser/zip/zipParser.java @@ -79,10 +79,11 @@ public class zipParser extends AbstractParser implements Parser { * a list of library names that are needed by this parser * @see Parser#getLibxDependences() */ - private static final String[] LIBX_DEPENDENCIES = new String[] {}; + private static final String[] LIBX_DEPENDENCIES = new String[] {}; public zipParser() { super(LIBX_DEPENDENCIES); + parserName = "Compressed Archive File Parser"; } public Hashtable getSupportedMimeTypes() { diff --git a/source/de/anomic/plasma/plasmaParser.java b/source/de/anomic/plasma/plasmaParser.java index e1551aaaf..41f8306ee 100644 --- a/source/de/anomic/plasma/plasmaParser.java +++ b/source/de/anomic/plasma/plasmaParser.java @@ -46,7 +46,6 @@ package de.anomic.plasma; import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -70,8 +69,10 @@ import java.util.Set; import de.anomic.htmlFilter.htmlFilterContentScraper; import de.anomic.htmlFilter.htmlFilterOutputStream; +import de.anomic.http.httpc; import de.anomic.plasma.parser.Parser; import de.anomic.plasma.parser.ParserException; +import de.anomic.plasma.parser.ParserInfo; import de.anomic.server.serverFileUtils; import de.anomic.server.logging.serverLog; @@ -92,7 +93,7 @@ public final class plasmaParser { * @see #loadEnabledParserList() * @see #setEnabledParserList(Enumeration) */ - private static final Properties enabledParserList = new Properties(); + private static final HashSet enabledParserList = new HashSet(); /** * A list of file extensions that are supported by all enabled parsers @@ -104,12 +105,43 @@ public final class plasmaParser { * be parsed in realtime. */ private static final HashSet supportedRealtimeFileExt = new HashSet(); + + /** + * A list of mimeTypes that are generic + */ + private static final HashSet genericMimeTypes = new HashSet(); + static { + genericMimeTypes.add("text/plain"); + genericMimeTypes.add("text/text"); + genericMimeTypes.add("text/xml"); + genericMimeTypes.add("application/xml"); + genericMimeTypes.add("application/x-xml"); + genericMimeTypes.add("application/octet-stream"); + genericMimeTypes.add("application/zip"); + genericMimeTypes.add("application/x-zip"); + genericMimeTypes.add("application/x-zip-compressed"); + genericMimeTypes.add("application/x-compress"); + genericMimeTypes.add("application/x-compressed"); + } /** * A list of mimeTypes that can be parsed in Realtime (on the fly) */ private static final HashSet realtimeParsableMimeTypes = new HashSet(); + private static final Properties mimeTypeLookupByFileExt = new Properties(); + static { + // loading a list of extensions from file + BufferedInputStream bufferedIn = null; + try { + mimeTypeLookupByFileExt.load(bufferedIn = new BufferedInputStream(new FileInputStream(new File("httpd.mime")))); + } catch (IOException e) { + System.err.println("ERROR: httpd.mime not found in settings path"); + } finally { + if (bufferedIn != null) try{bufferedIn.close();}catch(Exception e){} + } + } + /** * A pool of parsers. * @see plasmaParserPool @@ -162,7 +194,7 @@ public final class plasmaParser { // The maximum number of idle connections connections in the pool // 0 = no limit. - config.maxIdle = 10; + config.maxIdle = 5; config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK; config.minEvictableIdleTimeMillis = 30000; @@ -175,6 +207,8 @@ public final class plasmaParser { loadAvailableParserList(); } + private serverLog theLogger = new serverLog("PARSER"); + /** * This function is used to initialize the realtimeParsableMimeTypes List. * This list contains a list of mimeTypes that can be parsed in realtime by @@ -185,7 +219,7 @@ public final class plasmaParser { public static void initRealtimeParsableMimeTypes(String realtimeParsableMimeTypes) { LinkedList mimeTypes = new LinkedList(); if ((realtimeParsableMimeTypes == null) || (realtimeParsableMimeTypes.length() == 0)) { - + // Nothing todo here } else { String[] realtimeParsableMimeTypeList = realtimeParsableMimeTypes.split(","); for (int i = 0; i < realtimeParsableMimeTypeList.length; i++) mimeTypes.add(realtimeParsableMimeTypeList[i].toLowerCase().trim()); @@ -280,7 +314,7 @@ public final class plasmaParser { } synchronized (enabledParserList) { - return enabledParserList.containsKey(mimeType); + return enabledParserList.contains(mimeType); } } @@ -302,7 +336,7 @@ public final class plasmaParser { // termining last position of . in file path p = name.lastIndexOf('.'); - if (p < 0) return name; // seams to be strange, but this is a directory entry or default file (html) + if (p < 0) return ""; return name.substring(p + 1); } @@ -352,19 +386,8 @@ public final class plasmaParser { return ((pos < 0) ? mimeType : mimeType.substring(0, pos)); } - public static String getMimeTypeByFileExt(String fileExt) { - // loading a list of extensions from file - Properties prop = new Properties(); - BufferedInputStream bufferedIn = null; - try { - prop.load(bufferedIn = new BufferedInputStream(new FileInputStream(new File("httpd.mime")))); - } catch (IOException e) { - System.err.println("ERROR: httpd.mime not found in settings path"); - } finally { - if (bufferedIn != null) try{bufferedIn.close();}catch(Exception e){} - } - - return prop.getProperty(fileExt,"application/octet-stream"); + public static String getMimeTypeByFileExt(String fileExt) { + return mimeTypeLookupByFileExt.getProperty(fileExt,"application/octet-stream"); } public plasmaParser() { @@ -373,7 +396,7 @@ public final class plasmaParser { public static String[] setEnabledParserList(Set mimeTypeSet) { - Properties newEnabledParsers = new Properties(); + HashSet newEnabledParsers = new HashSet(); HashSet newSupportedFileExt = new HashSet(); if (mimeTypeSet != null) { @@ -384,7 +407,7 @@ public final class plasmaParser { Parser theParser = null; try { // getting the parser - theParser = (Parser) plasmaParser.theParserPool.borrowObject(availableParserList.get(mimeType)); + theParser = (Parser) plasmaParser.theParserPool.borrowObject(((ParserInfo)availableParserList.get(mimeType)).parserClassName); // getting a list of mimeTypes that the parser supports Hashtable parserSupportsMimeTypes = theParser.getSupportedMimeTypes(); @@ -397,7 +420,7 @@ public final class plasmaParser { newSupportedFileExt.addAll(Arrays.asList(extArray)); } } - newEnabledParsers.put(mimeType,availableParserList.get(mimeType)); + newEnabledParsers.add(mimeType); } catch (Exception e) { serverLog.logSevere("PARSER", "error in setEnabledParserList", e); @@ -411,7 +434,7 @@ public final class plasmaParser { synchronized (enabledParserList) { enabledParserList.clear(); - enabledParserList.putAll(newEnabledParsers); + enabledParserList.addAll(newEnabledParsers); } @@ -420,34 +443,18 @@ public final class plasmaParser { supportedFileExt.addAll(newSupportedFileExt); } - return (String[])newEnabledParsers.keySet().toArray(new String[newEnabledParsers.size()]); + return (String[])newEnabledParsers.toArray(new String[newEnabledParsers.size()]); } - public Hashtable getEnabledParserList() { + public HashSet getEnabledParserList() { synchronized (plasmaParser.enabledParserList) { - return (Hashtable) plasmaParser.enabledParserList.clone(); + return (HashSet) plasmaParser.enabledParserList.clone(); } } public Hashtable getAvailableParserList() { return plasmaParser.availableParserList; - } - - private static void loadEnabledParserList() { - // loading a list of availabe parser from file - Properties prop = new Properties(); - BufferedInputStream bufferedIn = null; - try { - prop.load(bufferedIn = new BufferedInputStream(new FileInputStream(new File("yacy.parser")))); - } catch (IOException e) { - System.err.println("ERROR: yacy.parser not found in settings path"); - } finally { - if (bufferedIn != null) try{ bufferedIn.close(); }catch(Exception e){} - } - - // enable them ... - setEnabledParserList(prop.keySet()); - } + } private static void loadAvailableParserList() { try { @@ -474,9 +481,11 @@ public final class plasmaParser { */ File[] parserDirectories = parserDir.listFiles(parserDirectoryFilter); if (parserDirectories == null) return; + for (int parserDirNr=0; parserDirNr< parserDirectories.length; parserDirNr++) { File currentDir = parserDirectories[parserDirNr]; serverLog.logFine("PARSER", "Searching in directory " + currentDir.toString()); + String[] parserClasses = currentDir.list(parserFileNameFilter); if (parserClasses == null) continue; @@ -506,12 +515,25 @@ public final class plasmaParser { // loading the list of mime-types that are supported by this parser class Hashtable supportedMimeTypes = ((Parser)theParser).getSupportedMimeTypes(); + + // creating a parser info object + ParserInfo parserInfo = new ParserInfo(); + parserInfo.parserClass = parserClass; + parserInfo.parserClassName = fullClassName; + parserInfo.libxDependencies = neededLibx; + parserInfo.supportedMimeTypes = supportedMimeTypes; + parserInfo.parserVersionNr = ((Parser)theParser).getVersion(); + parserInfo.parserName = ((Parser)theParser).getName(); + Iterator mimeTypeIterator = supportedMimeTypes.keySet().iterator(); while (mimeTypeIterator.hasNext()) { String mimeType = (String) mimeTypeIterator.next(); - availableParserList.put(mimeType,fullClassName); + availableParserList.put(mimeType,parserInfo ); serverLog.logInfo("PARSER", "Found functional parser for mimeType '" + mimeType + "'." + - ((neededLibxBuf.length()>0)?"\n Dependencies: " + neededLibxBuf.toString():"")); + "\n\tName: " + parserInfo.parserName + + "\n\tVersion: " + parserInfo.parserVersionNr + + "\n\tClass: " + parserInfo.parserClassName + + ((neededLibxBuf.length()>0)?"\n\tDependencies: " + neededLibxBuf.toString():"")); } } catch (Exception e) { /* we can ignore this for the moment */ @@ -537,50 +559,19 @@ public final class plasmaParser { try { theParserPool.close(); } catch (Exception e) { } - } + } public plasmaParserDocument parseSource(URL location, String mimeType, byte[] source) { - - Parser theParser = null; + File tempFile = null; try { - mimeType = getRealMimeType(mimeType); - String fileExt = getFileExt(location); - - // TODO: Handling of not trustable mimeTypes - // text/plain, octet-stream - if ( - (mimeType.equalsIgnoreCase("text/plain") && !fileExt.equalsIgnoreCase("txt")) || - (mimeType.equalsIgnoreCase("text/xml") && !fileExt.equalsIgnoreCase("txt")) - ) { - if (enabledParserList.containsKey("application/octet-stream")) { - mimeType = "application/octet-stream"; - } - } - - // getting the correct parser for the given mimeType - theParser = this.getParser(mimeType); - - // if a parser was found we use it ... - if (theParser != null) { - return theParser.parse(location, mimeType,source); - } else if (realtimeParsableMimeTypesContains(mimeType)) { - // ... otherwise we make a html scraper and transformer - htmlFilterContentScraper scraper = new htmlFilterContentScraper(location); - OutputStream hfos = new htmlFilterOutputStream(null, scraper, null, false); - hfos.write(source); - hfos.close(); - return transformScraper(location, mimeType, scraper); - } else { - return null; - } - } catch (Exception e) { - //e.printStackTrace(); + tempFile = File.createTempFile("parseSource", ".tmp"); + return parseSource(location, mimeType, tempFile); + } catch (Exception e) { return null; } finally { - if ((theParser != null) && (supportedMimeTypesContains(mimeType))) { - try { plasmaParser.theParserPool.returnObject(mimeType, theParser); } catch (Exception e) {} - } + if (tempFile != null) try { tempFile.delete(); } catch (Exception ex){} } + } public plasmaParserDocument parseSource(URL location, String mimeType, File sourceFile) { @@ -590,16 +581,58 @@ public final class plasmaParser { mimeType = getRealMimeType(mimeType); String fileExt = getFileExt(location); - // TODO: Handling of not trustable mimeTypes - // text/plain, octet-stream - if ( - (mimeType.equalsIgnoreCase("text/plain") && !fileExt.equalsIgnoreCase("txt")) || - (mimeType.equalsIgnoreCase("text/xml") && !fileExt.equalsIgnoreCase("txt")) - ) { - if (enabledParserList.containsKey("application/octet-stream")) { - mimeType = "application/octet-stream"; - } - } + if (this.theLogger.isFine()) + this.theLogger.logFine("Parsing " + location + " with mimeType '" + mimeType + + "' and file extension '" + fileExt + "'."); + + /* + * There are some problematic mimeType - fileExtension combination where we have to enforce + * a mimeType detection to get the proper parser for the content + * + * - application/zip + .odt + * - text/plain + .odt + * - text/plain + .vcf + * - text/xml + .rss + * - text/xml + .atom + * + * In all these cases we can trust the fileExtension and have to determine the proper mimeType. + * + */ + +// // Handling of not trustable mimeTypes +// // - text/plain +// // - text/xml +// // - application/octet-stream +// // - application/zip +// if ( +// (mimeType.equalsIgnoreCase("text/plain") && !fileExt.equalsIgnoreCase("txt")) || +// (mimeType.equalsIgnoreCase("text/xml") && !fileExt.equalsIgnoreCase("txt")) +// ) { +// if (this.theLogger.isFine()) +// this.theLogger.logFine("Document " + location + " has an mimeType '" + mimeType + +// "' that seems not to be correct for file extension '" + fileExt + "'."); +// +// if (enabledParserList.containsKey("application/octet-stream")) { +// theParser = this.getParser("application/octet-stream"); +// Object newMime = theParser.getClass().getMethod("getMimeType", new Class[]{File.class}).invoke(theParser, sourceFile); +// if (newMime == null) +// if (newMime instanceof String) { +// String newMimeType = (String)newMime; +// if ((newMimeType.equals("application/octet-stream")) { +// return null; +// } +// mimeType = newMimeType; +// } +// } else { +// return null; +// } +// } else if (mimeType.equalsIgnoreCase("application/zip") && fileExt.equalsIgnoreCase("odt")){ +// if (enabledParserList.containsKey("application/vnd.oasis.opendocument.text")) { +// mimeType = "application/vnd.oasis.opendocument.text"; +// } else { +// return null; +// } +// } // getting the correct parser for the given mimeType theParser = this.getParser(mimeType); @@ -647,16 +680,18 @@ public final class plasmaParser { * @param mimeType * @return */ - public Parser getParser(String mimeType) { + private Parser getParser(String mimeType) { mimeType = getRealMimeType(mimeType); try { // determining the proper parser class name for the mimeType String parserClassName = null; + ParserInfo parserInfo = null; synchronized (plasmaParser.enabledParserList) { - if (plasmaParser.enabledParserList.containsKey(mimeType)) { - parserClassName = (String)plasmaParser.enabledParserList.get(mimeType); + if (plasmaParser.enabledParserList.contains(mimeType)) { + parserInfo = (ParserInfo)plasmaParser.availableParserList.get(mimeType); + parserClassName = parserInfo.parserClassName; } else { return null; } @@ -668,6 +703,7 @@ public final class plasmaParser { // checking if the created parser really supports the given mimetype Hashtable supportedMimeTypes = theParser.getSupportedMimeTypes(); if ((supportedMimeTypes != null) && (supportedMimeTypes.containsKey(mimeType))) { + parserInfo.incUsageCounter(); return theParser; } theParserPool.returnObject(parserClassName,theParser); @@ -740,10 +776,40 @@ public final class plasmaParser { //javac -classpath lib/commons-collections.jar:lib/commons-pool-1.2.jar -sourcepath source source/de/anomic/plasma/plasmaParser.java //java -cp source:lib/commons-collections.jar:lib/commons-pool-1.2.jar de.anomic.plasma.plasmaParser bug.html bug.out try { - File in = new File(args[0]); - //File out = new File(args[1]); + File contentFile = null; + URL contentURL = null; + String contentMimeType = "application/octet-stream"; + + if (args.length < 2) { + System.err.println("Usage: java de.anomic.plasma.plasmaParser (-f filename|-u URL) [-m mimeType]"); + } + + String mode = args[0]; + if (mode.equalsIgnoreCase("-f")) { + contentFile = new File(args[1]); + contentURL = contentFile.toURL(); + } else if (mode.equalsIgnoreCase("-u")) { + contentURL = new URL(args[1]); + + // downloading the document content + byte[] contentBytes = httpc.singleGET(contentURL, 10000, null, null, null); + + contentFile = File.createTempFile("content",".tmp"); + contentFile.deleteOnExit(); + serverFileUtils.write(contentBytes, contentFile); + } + + if ((args.length == 4)&&(args[2].equalsIgnoreCase("-m"))) { + contentMimeType = args[3]; + } + + // creating a plasma parser plasmaParser theParser = new plasmaParser(); + + // configuring the realtime parsable mimeTypes plasmaParser.initRealtimeParsableMimeTypes("application/xhtml+xml,text/html,text/plain"); + + // configure all other supported mimeTypes plasmaParser.initParseableMimeTypes( "application/atom+xml," + "application/gzip," + @@ -763,14 +829,14 @@ public final class plasmaParser { "text/xml," + "application/x-bzip2," + "application/postscript," + - "text/x-vcard"); - FileInputStream theInput = new FileInputStream(in); - ByteArrayOutputStream theOutput = new ByteArrayOutputStream(); - serverFileUtils.copy(theInput, theOutput); - plasmaParserDocument document = theParser.parseSource(new URL("http://brain/~theli/test.ps"), null, theOutput.toByteArray()); - //plasmaParserDocument document = theParser.parseSource(new URL("http://brain.yacy"), "application/pdf", theOutput.toByteArray()); - //byte[] theText = document.getText(); - //serverFileUtils.write(theText, out); + "text/x-vcard," + + "application/vnd.oasis.opendocument.text," + + "application/x-vnd.oasis.opendocument.text"); + + // parsing the content + plasmaParserDocument document = theParser.parseSource(contentURL, contentMimeType, contentFile); + + // printing out all parsed sentences if (document != null) { String[] sentences = document.getSentences(); if (sentences != null) for (int i = 0; i < sentences.length; i++) System.out.println("line " + i + ":" + sentences[i]); diff --git a/source/de/anomic/plasma/plasmaSnippetCache.java b/source/de/anomic/plasma/plasmaSnippetCache.java index c7bc9ef3f..da3404b27 100644 --- a/source/de/anomic/plasma/plasmaSnippetCache.java +++ b/source/de/anomic/plasma/plasmaSnippetCache.java @@ -327,8 +327,9 @@ public class plasmaSnippetCache { if (header == null) { String filename = this.cacheManager.getCachePath(url).getName(); int p = filename.lastIndexOf('.'); - if ( + if ( // if no extension is available (p < 0) || + // or the extension is supported by one of the parsers ((p >= 0) && (plasmaParser.supportedFileExtContains(filename.substring(p + 1)))) ) { String supposedMime = "text/html"; diff --git a/source/de/anomic/server/logging/serverLog.java b/source/de/anomic/server/logging/serverLog.java index 5f3338f79..e34443455 100644 --- a/source/de/anomic/server/logging/serverLog.java +++ b/source/de/anomic/server/logging/serverLog.java @@ -81,69 +81,98 @@ public final class serverLog { public void setLevel(Level newLevel) { this.theLogger.setLevel(newLevel); } - + public void logSevere(String message) {this.theLogger.severe(message);} public void logSevere(String message, Throwable thrown) {this.theLogger.log(Level.SEVERE,message,thrown);} + public boolean isSevere() { return this.theLogger.isLoggable(Level.SEVERE); } public void logWarning(String message) {this.theLogger.warning(message);} public void logWarning(String message, Throwable thrown) {this.theLogger.log(Level.WARNING,message,thrown);} - + public boolean isWarning() { return this.theLogger.isLoggable(Level.WARNING); } + public void logConfig(String message) {this.theLogger.config(message);} public void logConfig(String message, Throwable thrown) {this.theLogger.log(Level.CONFIG,message,thrown);} + public boolean isConfig() { return this.theLogger.isLoggable(Level.CONFIG); } public void logInfo(String message) {this.theLogger.info(message);} public void logInfo(String message, Throwable thrown) {this.theLogger.log(Level.INFO,message,thrown);} + public boolean isInfo() { return this.theLogger.isLoggable(Level.INFO); } public void logFine(String message) {this.theLogger.fine(message);} public void logFine(String message, Throwable thrown) {this.theLogger.log(Level.FINE,message,thrown);} + public boolean isFine() { return this.theLogger.isLoggable(Level.FINE); } public void logFiner(String message) {this.theLogger.finer(message);} - public void logFiner(String message, Throwable thrown) {this.theLogger.log(Level.FINER,message,thrown);} + public void logFiner(String message, Throwable thrown) {this.theLogger.log(Level.FINER,message,thrown);} + public boolean isFiner() { return this.theLogger.isLoggable(Level.FINER); } public void logFinest(String message) {this.theLogger.finest(message);} - public void logFinest(String message, Throwable thrown) {this.theLogger.log(Level.FINEST,message,thrown);} + public void logFinest(String message, Throwable thrown) {this.theLogger.log(Level.FINEST,message,thrown);} + public boolean isFinest() { return this.theLogger.isLoggable(Level.FINEST); } + + private void log(Level level, String msg, Throwable thrown) { + this.theLogger.log(level, msg, thrown); + } public boolean isLoggable(Level level) { return this.theLogger.isLoggable(level); } + // static log messages: log everything private static void log(String appName, int messageLevel, String message) { Logger.getLogger(appName).log(Level.parse(Integer.toString(messageLevel)),message); } - private void log(Level level, String msg, Throwable thrown) { - this.theLogger.log(level, msg, thrown); - } + public static void logSevere(String appName, String message) { Logger.getLogger(appName).severe(message); } public static void logSevere(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.SEVERE,message,thrown); } + public static void isSevere(String appName) { + Logger.getLogger(appName).isLoggable(Level.SEVERE); + } + public static void logWarning(String appName, String message) { Logger.getLogger(appName).warning(message); } public static void logWarning(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.WARNING,message,thrown); } + public static void isWarning(String appName) { + Logger.getLogger(appName).isLoggable(Level.WARNING); + } + public static void logConfig(String appName, String message) { Logger.getLogger(appName).config(message); } public static void logConfig(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.CONFIG,message,thrown); } + public static void isConfig(String appName) { + Logger.getLogger(appName).isLoggable(Level.CONFIG); + } + public static void logInfo(String appName, String message) { Logger.getLogger(appName).info(message); } public static void logInfo(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.INFO,message,thrown); } + public static void isInfo(String appName) { + Logger.getLogger(appName).isLoggable(Level.INFO); + } + public static void logFine(String appName, String message) { Logger.getLogger(appName).fine(message); } public static void logFine(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.FINE,message,thrown); } + public static void isFine(String appName) { + Logger.getLogger(appName).isLoggable(Level.FINE); + } public static void logFiner(String appName, String message) { Logger.getLogger(appName).finer(message); @@ -151,6 +180,9 @@ public final class serverLog { public static void logFiner(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.FINER,message,thrown); } + public static void isFiner(String appName) { + Logger.getLogger(appName).isLoggable(Level.FINER); + } public static void logFinest(String appName, String message) { Logger.getLogger(appName).finest(message); @@ -158,6 +190,9 @@ public final class serverLog { public static void logFinest(String appName, String message, Throwable thrown) { Logger.getLogger(appName).log(Level.FINEST,message,thrown); } + public static void isFinest(String appName) { + Logger.getLogger(appName).isLoggable(Level.FINEST); + } public static final void configureLogging(File loggingConfigFile) throws SecurityException, FileNotFoundException, IOException { FileInputStream fileIn = null;