18
18
import java .awt .Graphics2D ;
19
19
import java .awt .RenderingHints ;
20
20
import java .awt .image .BufferedImage ;
21
- import java .io .BufferedInputStream ;
22
- import java .io .BufferedOutputStream ;
23
21
import java .io .BufferedReader ;
24
22
import java .io .ByteArrayOutputStream ;
25
23
import java .io .File ;
26
- import java .io .FileInputStream ;
27
24
import java .io .FileOutputStream ;
28
25
import java .io .FileReader ;
29
26
import java .io .IOException ;
30
27
import java .io .InputStream ;
31
- import java .io .OutputStream ;
32
28
import java .io .OutputStreamWriter ;
33
29
import java .io .Writer ;
34
30
import java .net .URL ;
37
33
import java .util .HashSet ;
38
34
import java .util .LinkedList ;
39
35
import java .util .List ;
36
+ import java .util .Properties ;
40
37
import java .util .Set ;
41
38
import java .util .regex .Matcher ;
42
39
import java .util .regex .Pattern ;
@@ -117,12 +114,12 @@ public void publish(List<Topic> topics,
117
114
publishTemplate (topics , title , feedCount , articleCount , htmlTemplate , new File ("index.html" ));
118
115
if (group .getRootDir () != null )
119
116
{
120
- copyFile (outputDir , "zeitgeist.css" , "zeitgeist.css" );
117
+ StreamUtils . copyFile (outputDir , new File ( group . getRootDir (), "zeitgeist.css" ) , "zeitgeist.css" );
121
118
}
122
119
else
123
120
{
124
121
125
- copyClasspathResource (outputDir , "zeitgeist.css" , "zeitgeist.css" );
122
+ StreamUtils . copyClasspathResource (outputDir , "zeitgeist.css" , "zeitgeist.css" );
126
123
}
127
124
128
125
if (group .isDefined ("snippet" ))
@@ -191,8 +188,8 @@ private void cacheImages(List<Topic> topics, File cacheDir)
191
188
{
192
189
try
193
190
{
194
- copyStream (openConnection (image .getImageURL ()).getInputStream (),
195
- new FileOutputStream ( new File (cacheDir , image .getCachedFileName () )));
191
+ StreamUtils . copyStreamToFile (openConnection (image .getImageURL ()).getInputStream (),
192
+ new File (cacheDir , image .getCachedFileName ()));
196
193
LOG .debug ("Downloaded image: " + image .getImageURL ());
197
194
scaleImage (cachedFile , 200 );
198
195
}
@@ -232,8 +229,7 @@ private void cacheIcons(List<Topic> topics, File cacheDir)
232
229
{
233
230
try
234
231
{
235
- copyStream (openConnection (icon .getImageURL ()).getInputStream (),
236
- new FileOutputStream (cachedFile ));
232
+ StreamUtils .copyStreamToFile (openConnection (icon .getImageURL ()).getInputStream (), cachedFile );
237
233
// Some sites will serve up a zero-byte file for the default location
238
234
// but still have a valid icon elsewhere.
239
235
if (cachedFile .length () == 0 )
@@ -270,8 +266,7 @@ private void extractFaviconFromHTML(Image icon, File cachedFile)
270
266
if (matcher .find ())
271
267
{
272
268
URL url = new URL (icon .getArticleURL (), matcher .group (1 ));
273
- copyStream (openConnection (url ).getInputStream (),
274
- new FileOutputStream (cachedFile ));
269
+ StreamUtils .copyStreamToFile (openConnection (url ).getInputStream (), cachedFile );
275
270
LOG .debug ("Downloaded favicon via web page: " + url .toString ());
276
271
}
277
272
else
@@ -298,7 +293,7 @@ private String fetchPage(URL pageURL) throws IOException
298
293
URLConnection urlConnection = openConnection (pageURL );
299
294
InputStream inputStream = urlConnection .getInputStream ();
300
295
ByteArrayOutputStream buffer = new ByteArrayOutputStream ();
301
- copyStream (inputStream , buffer );
296
+ StreamUtils . copyStream (inputStream , buffer );
302
297
String encoding = urlConnection .getContentEncoding ();
303
298
return new String (buffer .toByteArray (), encoding == null ? ENCODING : encoding );
304
299
}
@@ -343,128 +338,76 @@ private URLConnection openConnection(URL url) throws IOException
343
338
344
339
345
340
/**
346
- * Copy a single named resource from the classpath to the output directory.
347
- * @param outputDirectory The destination directory for the copied resource.
348
- * @param resourcePath The path of the resource.
349
- * @param targetFileName The name of the file created in {@literal outputDirectory}.
350
- * @throws IOException If the resource cannot be copied.
341
+ * Entry point for the publisher application. Takes two mandatory arguments - the path to a file containing a list
342
+ * of feeds and the title to use for the generated output, and optionally a third argument specifying templates
343
+ * to use in place of the defaults.
351
344
*/
352
- private void copyClasspathResource (File outputDirectory ,
353
- String resourcePath ,
354
- String targetFileName ) throws IOException
355
- {
356
- InputStream resourceStream = ClassLoader .getSystemResourceAsStream (resourcePath );
357
- copyStream (resourceStream , new FileOutputStream (new File (outputDirectory , targetFileName )));
358
- }
359
-
360
-
361
- /**
362
- * Copy a single named file to the output directory.
363
- * @param outputDirectory The destination directory for the copied resource.
364
- * @param filePath The path of the file.
365
- * @param targetFileName The name of the file created in {@literal outputDirectory}.
366
- * @throws IOException If the file cannot be copied.
367
- */
368
- private void copyFile (File outputDirectory ,
369
- String filePath ,
370
- String targetFileName ) throws IOException
345
+ public static void main (String [] args ) throws IOException
371
346
{
372
- FileInputStream inputStream = new FileInputStream (new File (group .getRootDir (), filePath ));
373
- try
374
- {
375
- copyStream (inputStream , new FileOutputStream (new File (outputDirectory , targetFileName )));
376
- }
377
- finally
347
+ if (args .length < 2 || args .length > 3 )
378
348
{
379
- inputStream . close ();
349
+ printUsage ();
380
350
}
381
- }
382
-
383
-
384
- /**
385
- * Helper method to copy the contents of a stream to a file.
386
- * @param stream The stream to copy.
387
- * @param target The target stream to write the stream contents to.
388
- * @throws IOException If the stream cannot be copied.
389
- */
390
- private void copyStream (InputStream stream ,
391
- OutputStream target ) throws IOException
392
- {
393
- BufferedInputStream input = new BufferedInputStream (stream );
394
- try
351
+ else
395
352
{
396
- BufferedOutputStream output = new BufferedOutputStream ( target );
353
+ InputStream propertiesStream = Publisher . class . getClassLoader (). getResourceAsStream ( "zeitgeist.properties" );
397
354
try
398
355
{
399
- int i = input .read ();
400
- while (i != -1 )
401
- {
402
- output .write (i );
403
- i = input .read ();
404
- }
405
- output .flush ();
356
+ Properties properties = new Properties ();
357
+ properties .load (propertiesStream );
358
+ System .getProperties ().putAll (properties );
359
+
360
+ List <URL > feeds = parseFeedList (args [0 ]);
361
+
362
+ long maxAgeHours = Long .parseLong (System .getProperty ("zeitgeist.maxArticleAgeHours" ));
363
+ Date cutoffDate = new Date (System .currentTimeMillis () - Math .round (maxAgeHours * 3600000 ));
364
+ List <Article > articles = new ArticleFetcher ().getArticles (feeds , cutoffDate );
365
+ List <Topic > topics = new Zeitgeist (articles ,
366
+ Integer .parseInt (System .getProperty ("zeitgeist.minArticlesPerTopic" )),
367
+ Integer .parseInt (System .getProperty ("zeitgeist.minSourcesPerTopic" )),
368
+ Integer .parseInt (System .getProperty ("zeitgeist.minArticleRelevance" ))).getTopics ();
369
+ LOG .info (topics .size () + " topics identified." );
370
+ Publisher publisher = args .length > 2 ? new Publisher (new File (args [2 ])) : new Publisher ();
371
+ publisher .publish (topics , args [1 ], feeds .size (), articles .size (), new File ("." ));
406
372
}
407
373
finally
408
374
{
409
- output .close ();
375
+ propertiesStream .close ();
410
376
}
411
377
}
412
- finally
413
- {
414
- input .close ();
415
- }
416
378
}
417
379
418
380
419
- /**
420
- * Entry point for the publisher application. Takes three arguments - the path to a file containing a list
421
- * of feeds, the title to use for the generated output, and the maximum age (in hours) permitted for articles
422
- * to be included.
423
- */
424
- public static void main (String [] args ) throws IOException
381
+ private static List <URL > parseFeedList (String arg ) throws IOException
425
382
{
426
- if (args .length < 3 || args .length > 4 )
427
- {
428
- printUsage ();
429
- }
430
- else
383
+ List <URL > feeds = new LinkedList <URL >();
384
+ BufferedReader feedListReader = new BufferedReader (new FileReader (arg ));
385
+ try
431
386
{
432
- BufferedReader feedListReader = new BufferedReader (new FileReader (args [0 ]));
433
- try
387
+ for (String line = feedListReader .readLine (); line != null ; line = feedListReader .readLine ())
434
388
{
435
- List <URL > feeds = new LinkedList <URL >();
436
- for (String line = feedListReader .readLine (); line != null ; line = feedListReader .readLine ())
389
+ String url = line .trim ();
390
+ // Lines beginning with a hash are considered to be comments.
391
+ if (!url .startsWith ("#" ) && !url .isEmpty ())
437
392
{
438
- String url = line .trim ();
439
- // Lines beginning with a hash are considered to be comments.
440
- if (!url .startsWith ("#" ) && url .length () > 0 )
441
- {
442
- feeds .add (new URL (url ));
443
- }
393
+ feeds .add (new URL (url ));
444
394
}
445
- double maxAgeHours = Double .parseDouble (args [2 ]);
446
- Date cutoffDate = new Date (System .currentTimeMillis () - Math .round (maxAgeHours * 3600000 ));
447
- List <Article > articles = new ArticleFetcher ().getArticles (feeds , cutoffDate );
448
- List <Topic > topics = new Zeitgeist (articles ).getTopics ();
449
- LOG .info (topics .size () + " topics identified." );
450
- Publisher publisher = args .length > 3 ? new Publisher (new File (args [3 ])) : new Publisher ();
451
- publisher .publish (topics , args [1 ], feeds .size (), articles .size (), new File ("." ));
452
- }
453
- finally
454
- {
455
- feedListReader .close ();
456
395
}
457
396
}
397
+ finally
398
+ {
399
+ feedListReader .close ();
400
+ }
401
+ return feeds ;
458
402
}
459
403
460
404
461
405
private static void printUsage ()
462
406
{
463
- System .err .println ("java -jar zeitgeist-publisher.jar <feedlist> <title> <maxage> [templatedir]" );
407
+ System .err .println ("java -jar zeitgeist-publisher.jar <feedlist> <title> [templatedir]" );
464
408
System .err .println ();
465
409
System .err .println (" <feedlist> - Path to a file listing RSS/Atom feeds, one per line." );
466
410
System .err .println (" <title> - A title passed to the templates." );
467
- System .err .println (" <maxage> - The maximum age (in hours) of included articles." );
468
411
System .err .println (" [templatedir] - Path to alternate templates to use in place of the defaults." );
469
412
System .err .println ();
470
413
System .err .println ("If no template directory is specified, default templates from the classpath are used." );
0 commit comments