Skip to content

Commit 102d8df

Browse files
author
Jerome Charron
committed
NUTCH-88, Final step implementation:
* Add a parse utility that loops over the ordered list of parser defined for a content-type (until a parser return a Parse object). * Add a parse utility that returns a Parse object using a specified parser (mainly used in unit tests). * Make use of this utility in classes that needs to parse some content. git-svn-id: https://svn.apache.org/repos/asf/lucene/nutch/trunk@321231 13f79535-47bb-0310-9956-ffa450edef68
1 parent 33d603c commit 102d8df

16 files changed

Lines changed: 205 additions & 65 deletions

File tree

src/java/org/apache/nutch/fetcher/Fetcher.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,10 @@ private ParseStatus handleFetch(FetchListEntry fle, ProtocolOutput output) {
246246
return null;
247247
}
248248
String contentType = content.getContentType();
249-
Parser parser = null;
250249
Parse parse = null;
251250
ParseStatus status = null;
252251
try {
253-
parser = ParserFactory.getParser(contentType, url);
254-
parse = parser.getParse(content);
252+
parse = ParseUtil.parse(content);
255253
status = parse.getData().getStatus();
256254
} catch (Exception e) {
257255
e.printStackTrace();
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* Copyright 2005 The Apache Software Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.nutch.parse;
17+
18+
// JDK imports
19+
import java.util.logging.Logger;
20+
21+
// Nutch Imports
22+
import org.apache.nutch.protocol.Content;
23+
import org.apache.nutch.util.LogFormatter;
24+
25+
26+
/**
27+
* A Utility class containing methods to simply perform parsing utilities such
28+
* as iterating through a preferred list of {@link Parser}s to obtain
29+
* {@link Parse} objects.
30+
*
31+
* @author mattmann
32+
* @author Jérôme Charron
33+
* @author Sébastien Le Callonnec
34+
*/
35+
public class ParseUtil {
36+
37+
/* our log stream */
38+
public static final Logger LOG = LogFormatter.getLogger(ParseUtil.class
39+
.getName());
40+
41+
/** No public constructor */
42+
private ParseUtil() { }
43+
44+
/**
45+
* Performs a parse by iterating through a List of preferred {@Parser}s
46+
* until a successful parse is performed and a {@link Parse} object is
47+
* returned. If the parse is unsuccessful, a message is logged to the
48+
* <code>WARNING</code> level, and an empty parse is returned.
49+
*
50+
* @param content The content to try and parse.
51+
* @return A {@link Parse} object containing the parsed data.
52+
* @throws ParseException If no suitable parser is found to perform the parse.
53+
*/
54+
public final static Parse parse(Content content) throws ParseException {
55+
Parser[] parsers = null;
56+
57+
try {
58+
parsers = ParserFactory.getParsers(content.getContentType(), "");
59+
} catch (ParserNotFound e) {
60+
LOG.warning("No suitable parser found when trying to parse content " +
61+
content);
62+
throw new ParseException(e.getMessage());
63+
}
64+
65+
Parse parse = null;
66+
for (int i=0; i<parsers.length; i++) {
67+
parse = parsers[i].getParse(content);
68+
if ((parse != null) && (parse.getData().getStatus().isSuccess())) {
69+
return parse;
70+
}
71+
}
72+
73+
LOG.warning("Unable to successfully parse content " + content.getUrl() +
74+
" of type " + content.getContentType());
75+
76+
return new ParseStatus().getEmptyParse();
77+
}
78+
79+
/**
80+
* Method parses a {@link Content} object using the {@link Parser} specified
81+
* by the parameter <code>parserId</code>. If a suitable {@link Parser} is not
82+
* found, then a <code>WARNING</code> level message is logged, and a
83+
* ParseException is thrown.
84+
* If the parse is uncessful for any other reason, then a <code>WARNING</code>
85+
* level message is logged, and a <code>ParseStatus.getEmptyParse() is
86+
* returned.
87+
*
88+
* @param parserId The ID of the {@link Parser} to use to parse the specified
89+
* content.
90+
* @param content The content to parse.
91+
* @return A {@link Parse} object if the parse is successful, otherwise,
92+
* a <code>ParseStatus.getEmptyParse()</code>.
93+
* @throws ParseException If there is no suitable {@link Parser} found
94+
* to perform the parse.
95+
*/
96+
public final static Parse parseByParserId(String parserId, Content content)
97+
throws ParseException {
98+
Parse parse = null;
99+
Parser p = null;
100+
101+
try {
102+
p = ParserFactory.getParserById(parserId);
103+
} catch (ParserNotFound e) {
104+
LOG.warning("No suitable parser found when trying to parse content " +
105+
content);
106+
throw new ParseException(e.getMessage());
107+
}
108+
109+
parse = p.getParse(content);
110+
111+
if (parse != null && parse.getData().getStatus().isSuccess()) {
112+
return parse;
113+
} else {
114+
LOG.warning("Unable to successfully parse content " + content.getUrl() +
115+
" of type " + content.getContentType());
116+
return new ParseStatus().getEmptyParse();
117+
}
118+
}
119+
120+
}

src/java/org/apache/nutch/parse/ParserChecker.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import org.apache.nutch.util.LogFormatter;
2020

21+
import org.apache.nutch.parse.ParseUtil;
22+
2123
import org.apache.nutch.protocol.ProtocolFactory;
2224
import org.apache.nutch.protocol.Protocol;
2325
import org.apache.nutch.protocol.Content;
@@ -83,8 +85,7 @@ public static void main(String[] args) throws Exception {
8385
LOG.info("parsing: "+url);
8486
LOG.info("contentType: "+contentType);
8587

86-
Parser parser = ParserFactory.getParser(contentType, url);
87-
Parse parse = parser.getParse(content);
88+
Parse parse = ParseUtil.parse(content);
8889

8990
System.out.print("---------\nParseData\n---------\n");
9091
System.out.print(parse.getData().toString());

src/java/org/apache/nutch/parse/ParserFactory.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,54 @@ public static Parser[] getParsers(String contentType, String url)
173173
return (Parser[]) parsers.toArray(new Parser[]{});
174174
}
175175

176+
/**
177+
* <p>Function returns a {@link Parser} instance with the specified <code>parserId</code>.
178+
* If the Parser instance isn't found, then the function throws a <code>ParserNotFound</code>
179+
* exception. If the function is able to find the {@link Parser} in the internal <code>PARSER_CACHE</code>
180+
* then it will return the already instantiated Parser. Otherwise, if it has to instantiate the Parser itself
181+
* , then this function will cache that Parser in the internal <code>PARSER_CACHE</code>.
182+
*
183+
* @param parserId The string ID (e.g., "parse-text", "parse-msword") of the {@link Parser} implementation to return.
184+
* @return A {@link Parser} implementation specified by the parameter <code>parserId</code>.
185+
* @throws ParserNotFound If the Parser is not found (i.e., registered with the extension point), or if the there a {@link PluginRuntimeException}
186+
* instantiating the {@link Parser}.
187+
*/
188+
public static Parser getParserById(String parserId) throws ParserNotFound{
189+
//first check the cache
190+
191+
if(PARSER_CACHE.get(parserId) != null){
192+
return (Parser)PARSER_CACHE.get(parserId);
193+
}
194+
else{
195+
//get the list of registered parsing extensions
196+
//then find the right one by Id
197+
198+
Extension[] extensions = X_POINT.getExtensions();
199+
Extension parserExt = getExtensionById(extensions,parserId);
200+
201+
if (parserExt == null) {
202+
throw new ParserNotFound("No Parser Found for parserId: "
203+
+ parserId + "!");
204+
} else {
205+
// instantiate the Parser
206+
try {
207+
Parser p = null;
208+
p = (Parser) parserExt.getExtensionInstance();
209+
PARSER_CACHE
210+
.put(parserId, p);
211+
return p;
212+
} catch (PluginRuntimeException e) {
213+
LOG.warning("ParserFactory:PluginRuntimeException when "
214+
+ "initializing parser plugin "
215+
+ parserExt.getDescriptor().getPluginId()
216+
+ " instance in getParserById");
217+
throw new ParserNotFound("No Parser Found for parserId: "
218+
+ parserId + "!");
219+
}
220+
}
221+
}
222+
}
223+
176224
/**
177225
* finds the best-suited parse plugin for a given contentType.
178226
*

src/java/org/apache/nutch/parse/ParserNotFound.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.apache.nutch.parse;
1817

19-
import java.io.IOException;
20-
2118
public class ParserNotFound extends ParseException {
19+
20+
private static final long serialVersionUID=23993993939L;
2221
private String url;
2322
private String contentType;
2423

24+
public ParserNotFound(String message){
25+
super(message);
26+
}
27+
2528
public ParserNotFound(String url, String contentType) {
2629
this(url, contentType,
2730
"parser not found for contentType="+contentType+" url="+url);

src/java/org/apache/nutch/tools/ParseSegment.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,7 @@ private void handleContent(FetcherOutput fo, Content content)
230230
return;
231231
}
232232

233-
Parser parser = ParserFactory.getParser(contentType, url);
234-
Parse parse = parser.getParse(content);
233+
Parse parse = ParseUtil.parse(content);
235234
outputPage(new ParseText(parse.getText()), parse.getData());
236235

237236
} else {
@@ -585,7 +584,7 @@ public static void main(String[] args) throws Exception {
585584

586585
parseSegment.setLogLevel
587586
(Level.parse((new String(logLevel)).toUpperCase()));
588-
587+
589588
if (threadCount != -1)
590589
parseSegment.setThreadCount(threadCount);
591590
if (showThreadID)

src/plugin/creativecommons/src/test/org/creativecommons/nutch/TestCCParseFilter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
package org.creativecommons.nutch;
1818

19-
import org.apache.nutch.parse.*;
19+
import org.apache.nutch.parse.Parse;
20+
import org.apache.nutch.parse.ParseUtil;
2021
import org.apache.nutch.protocol.Content;
2122

2223
import java.util.Properties;
@@ -54,10 +55,9 @@ public void pageTest(File file, String url,
5455
in.close();
5556
byte[] bytes = out.toByteArray();
5657

57-
Parser parser = ParserFactory.getParser(contentType, url);
5858
Content content =
5959
new Content(url, url, bytes, contentType, new Properties());
60-
Parse parse = parser.getParse(content);
60+
Parse parse = ParseUtil.parseByParserId("parse-html",content);
6161

6262
Properties metadata = parse.getData().getMetadata();
6363
assertEquals(license, metadata.get("License-Url"));

src/plugin/parse-ext/src/test/org/apache/nutch/parse/ext/TestExtParser.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
import org.apache.nutch.protocol.Content;
2222
import org.apache.nutch.protocol.ProtocolException;
2323

24-
import org.apache.nutch.parse.ParserFactory;
25-
import org.apache.nutch.parse.Parser;
24+
import org.apache.nutch.parse.util.ParseUtil;
2625
import org.apache.nutch.parse.Parse;
2726
import org.apache.nutch.parse.ParseException;
2827

@@ -46,8 +45,7 @@
4645
public class TestExtParser extends TestCase {
4746
private File tempFile = null;
4847
private String urlString = null;
49-
private Content content = null;;
50-
private Parser parser = null;;
48+
private Content content = null;
5149
private Parse parse = null;
5250

5351
private String expectedText = "nutch rocks nutch rocks nutch rocks";
@@ -107,15 +105,13 @@ public void testIt() throws ParseException {
107105
// check external parser that does 'cat'
108106
contentType = "application/vnd.nutch.example.cat";
109107
content.setContentType(contentType);
110-
parser = ParserFactory.getParser(contentType, urlString);
111-
parse = parser.getParse(content);
108+
parse = ParseUtil.parse(content);
112109
assertEquals(expectedText,parse.getText());
113110

114111
// check external parser that does 'md5sum'
115112
contentType = "application/vnd.nutch.example.md5sum";
116113
content.setContentType(contentType);
117-
parser = ParserFactory.getParser(contentType, urlString);
118-
parse = parser.getParse(content);
114+
parse = ParseUtil.parse(content);
119115
assertTrue(parse.getText().startsWith(expectedMD5sum));
120116
}
121117
}

src/plugin/parse-mp3/src/test/org/apache/nutch/parse/mp3/TestMP3Parser.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import junit.framework.TestCase;
2020
import org.apache.nutch.parse.Parse;
2121
import org.apache.nutch.parse.ParseException;
22-
import org.apache.nutch.parse.Parser;
22+
import org.apache.nutch.parse.ParseUtil;
2323
import org.apache.nutch.parse.ParserFactory;
2424
import org.apache.nutch.protocol.Content;
2525
import org.apache.nutch.protocol.Protocol;
@@ -60,15 +60,13 @@ public void testId3v2() throws ProtocolException, ParseException {
6060
String urlString;
6161
Protocol protocol;
6262
Content content;
63-
Parser parser;
6463
Parse parse;
6564

6665
urlString = "file:" + sampleDir + fileSeparator + id3v2;
6766
protocol = ProtocolFactory.getProtocol(urlString);
6867
content = protocol.getContent(urlString);
6968

70-
parser = ParserFactory.getParser(content.getContentType(), urlString);
71-
parse = parser.getParse(content);
69+
parse = ParseUtil.parseByParserId("parse-mp3",content);
7270
Properties metadata = parse.getData().getMetadata();
7371
assertEquals("postgresql comment id3v2", metadata.getProperty("COMM-Text"));
7472
assertEquals("postgresql composer id3v2", metadata.getProperty("TCOM-Text"));

src/plugin/parse-mspowerpoint/src/test/org/apache/nutch/parse/mspowerpoint/TestMSPowerPointParser.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@
2929

3030
import org.apache.nutch.parse.Parse;
3131
import org.apache.nutch.parse.ParseData;
32-
import org.apache.nutch.parse.Parser;
33-
import org.apache.nutch.parse.ParserFactory;
32+
import org.apache.nutch.parse.util.ParseUtil;
3433
import org.apache.nutch.protocol.Content;
3534
import org.apache.nutch.protocol.Protocol;
3635
import org.apache.nutch.protocol.ProtocolFactory;
@@ -123,9 +122,7 @@ protected void tearDown() throws Exception {
123122
*/
124123
public void testContent() throws Exception {
125124

126-
Parser parser = ParserFactory.getParser(this.content.getContentType(),
127-
this.urlString);
128-
Parse parse = parser.getParse(this.content);
125+
Parse parse = ParseUtil.parseByParserId("parse-mspowerpoint",this.content);
129126

130127
ParseData data = parse.getData();
131128
String text = parse.getText();
@@ -162,10 +159,8 @@ public void testContent() throws Exception {
162159
*/
163160
public void testMeta() throws Exception {
164161

165-
Parser parser = ParserFactory.getParser(this.content.getContentType(),
166-
this.urlString);
167-
Parse parse = parser.getParse(this.content);
168-
162+
Parse parse = ParseUtil.parseByParserId("parse-mspowerpoint",content);
163+
169164
ParseData data = parse.getData();
170165

171166
final FileExtensionFilter titleFilter = new FileExtensionFilter(

0 commit comments

Comments
 (0)