001package Torello.HTML;
002
003import java.io.*;
004import java.util.Vector;
005import java.net.URL;
006import Torello.HTML.HTMLPage.Parser;
007
008import java.util.concurrent.*;
009import java.util.concurrent.locks.*;
010
011import Torello.JavaDoc.JDHeaderBackgroundImg;
012import Torello.JavaDoc.StaticFunctional;
013import Torello.JavaDoc.Excuse;
014
015/**
016 * A carbon-copy of class {@link HTMLPage}, augmented with a mechanism for setting <B>a timeout</B> 
017 * so that when scraping web-pages and {@code URL's} from servers that might have a tendency to hang,
018 * freeze, or delay - the Java Virtual Machine can skip and move-on when that timeout expires. 
019 * 
020 * <BR /><BR />
021 * <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_MWT>
022 * <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE>
023 * 
024 * @see Scrape#getHTML(BufferedReader, int, int)
025 * @see Scrape#getHTML(BufferedReader, String, String)
026 * @see HTMLPage
027 */
028@StaticFunctional(Excused="parser", Excuses=Excuse.SINGLETON)
029@JDHeaderBackgroundImg
030public class HTMLPageMWT
031{
032    private HTMLPageMWT() { }
033
034    /**
035     * If needing to "swap a proprietary parser" comes up, this is possible.
036     * It just needs to accept the same parameters as the current parser, and produce a 
037     * {@code Vector<HTMLNode>.}  This is not an advised step to take, but if an alternative
038     * parser has been tested and happens to be generating different results, it can be easily
039     * 'swapped out' for the one used now.
040     * @see HTMLPage.Parser
041     * @see HTMLPage.Parser#parse(CharSequence, boolean, String, String, String)
042     */
043    public static Parser parser = Torello.HTML.HelperPackages.parse.ParserRE::parsePageTokens;
044
045
046    // ********************************************************************************************
047    // ********************************************************************************************
048    // These 6 functions presume that the HTML source is from a URL
049    // ********************************************************************************************
050    // ********************************************************************************************
051
052
053    /**
054     * Convenience Method.
055     * <BR />Accepts: {@code URL} and Time-Out Parameters {@code 'timeout' & 'unit'}
056     * <BR />Passes null to parameters
057     * {@code startTag, endTag, rawHTMLFile, matchesFile & justTextFile}.
058     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, URL, boolean, String, String,
059     *      String, String, String)}
060     */
061    public static Vector<HTMLNode> getPageTokens
062        (long timeout, TimeUnit unit, URL url, boolean eliminateHTMLTags)
063        throws IOException, InterruptedException
064    {
065        return getPageTokens(timeout, unit, url, eliminateHTMLTags, null, null, null, null, null);
066    }
067
068    /**
069     * Convenience Method.
070     * <BR />Accepts: {@code URL} and Time-Out Parameters {@code 'timeout' & 'unit'}
071     * <BR />And-Accepts: {@code 'startTag'} and {@code 'endTag'}
072     * <BR />Passes null to parameters {@code rawHTMLFile, matchesFile & justTextFile}.
073     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, URL, boolean, String, String,
074     *      String, String, String)}
075     */ 
076    public static Vector<HTMLNode> getPageTokens(
077            long timeout, TimeUnit unit,
078            URL url, boolean eliminateHTMLTags,
079            String startTag, String endTag
080        )
081        throws IOException, InterruptedException
082    {
083        return getPageTokens
084            (timeout, unit, url, eliminateHTMLTags, startTag, endTag, null, null, null);
085    }
086
087    /**
088     * Convenience Method.
089     * <BR />Accepts: {@code URL} and Time-Out Parameters {@code 'timeout' & 'unit'}
090     * <BR />And-Accepts: {@code 'startLineNum'} and {@code 'endLineNum'}
091     * <BR />Passes null to parameters {@code rawHTMLFile, matchesFile & justTextFile}.
092     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, URL, boolean, int, int,
093     *      String, String, String)}
094     */
095    public static Vector<HTMLNode> getPageTokens(
096            long timeout, TimeUnit unit,
097            URL url, boolean eliminateHTMLTags,
098            int startLineNum, int endLineNum
099        )
100        throws IOException, InterruptedException
101    {
102        return getPageTokens
103            (timeout, unit, url, eliminateHTMLTags, startLineNum, endLineNum, null, null, null);
104    }
105
106    /**
107     * Convenience Method.
108     * <BR />Accepts: {@code URL} and Time-Out Parameters {@code 'timeout' & 'unit'}
109     * <BR />Passes null to {@code startTag} &amp; {@code endTag} parameters.
110     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, URL, boolean, String, String,
111     *      String, String, String)}
112     */
113    public static Vector<HTMLNode> getPageTokens(
114            long timeout, TimeUnit unit,
115            URL url, boolean eliminateHTMLTags,
116            String rawHTMLFile, String matchesFile, String justTextFile
117        )
118        throws IOException, InterruptedException
119    {
120        return getPageTokens(
121            timeout, unit, url, eliminateHTMLTags, null, null,
122            rawHTMLFile, matchesFile, justTextFile
123        );
124    }
125
126
127    // ********************************************************************************************
128    // ********************************************************************************************
129    // The next 6 functions presume that the input is from a BufferedReader
130    // ********************************************************************************************
131    // ********************************************************************************************
132
133    /**
134     * Convenience Method.
135     * <BR />Accepts: {@code BufferedReader}
136     * <BR />Passes null to parameters
137     * {@code startTag, endTag, rawHTMLFile, matchesFile & justTextFile}.
138     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, BufferedReader, boolean,
139     *      String, String, String, String, String)}
140     */
141    public static Vector<HTMLNode> getPageTokens
142        (long timeout, TimeUnit unit, BufferedReader br, boolean eliminateHTMLTags)
143        throws IOException, InterruptedException
144    {
145        return getPageTokens
146            (timeout, unit, br, eliminateHTMLTags, null, null, null, null, null);
147    }
148
149    /**
150     * Convenience Method.
151     * <BR />Accepts: {@code BufferedReader}
152     * <BR />And-Accepts: {@code 'startTag'} and {@code 'endTag'}
153     * <BR />Passes null to parameters {@code rawHTMLFile, matchesFile & justTextFile}.
154     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, BufferedReader, boolean,
155     *      String, String, String, String, String)}
156     */ 
157    public static Vector<HTMLNode> getPageTokens(
158            long timeout, TimeUnit unit,
159            BufferedReader br, boolean eliminateHTMLTags, String startTag, String endTag
160        )
161        throws IOException, InterruptedException
162    {
163        return getPageTokens
164            (timeout, unit, br, eliminateHTMLTags, startTag, endTag, null, null, null);
165    }
166
167    /**
168     * Convenience Method.
169     * <BR />Accepts: {@code BufferedReader}
170     * <BR />And-Accepts: {@code 'startLineNum'} and {@code 'endLineNum'}
171     * <BR />Passes null to parameters {@code rawHTMLFile, matchesFile & justTextFile}.
172     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, BufferedReader, boolean,
173     *      int, int, String, String, String)}
174     */
175    public static Vector<HTMLNode> getPageTokens(
176            long timeout, TimeUnit unit,
177            BufferedReader br, boolean eliminateHTMLTags,
178            int startLineNum, int endLineNum
179        )
180        throws IOException, InterruptedException
181    {
182        return getPageTokens
183            (timeout, unit, br, eliminateHTMLTags, startLineNum, endLineNum, null, null, null);
184    }
185
186    /**
187     * Convenience Method.
188     * <BR />Accepts: {@code BufferedReader}
189     * <BR />Passes null to {@code startTag} &amp; {@code endTag} parameters.
190     * <BR />Invokes: {@link #getPageTokens(long, TimeUnit, BufferedReader, boolean,
191     *      String, String, String, String, String)}
192     */
193    public static Vector<HTMLNode> getPageTokens(
194            long timeout, TimeUnit unit,
195            BufferedReader br, boolean eliminateHTMLTags,
196            String rawHTMLFile, String matchesFile, String justTextFile
197        )
198        throws IOException, InterruptedException
199    { 
200        return getPageTokens
201            (timeout, unit, br, eliminateHTMLTags, null, null, rawHTMLFile, matchesFile, justTextFile);
202    }
203
204
205    // ********************************************************************************************
206    // ********************************************************************************************
207    // * Receives a "pre-instantiated" BufferedReader for the HTML Source parameter
208    // ********************************************************************************************
209    // ********************************************************************************************
210
211
212    private static final ExecutorService    executor    = Executors.newCachedThreadPool();
213    private static final Lock               lock        = new ReentrantLock();
214
215    /**
216     * If this class has been used to make "multi-threaded" calls that use a Time-Out wait-period,
217     * you might see your Java-Program hang for a few seconds when you would expect it to exit back
218     * to your O.S. normally.
219     *
220     * <BR /><BR /><B>Max Wait Time</B> operates by building a "Timeout &amp; Monitor" thread, and
221     * therefore when a program you have written yourself reaches the end of its code, <I><B>if you
222     * have performed any Internet-Downloads using {@code class HTMLPageMWT}</B></I>, then your
223     * program <I>might not exit immediately,</I> but rather sit at the command-prompt for anywhere
224     * between 10 and 30 seconds before this Timeout-Thread, created in class HTMLPageMWT, dies.
225     *
226     * <BR /><BR /><B CLASS=JDDescLabel>Multi-Threaded:</B>
227     * 
228     * <BR />You may also immediately terminate any additional threads that were started by using
229     * this method.
230     */
231    public static void shutdownMWTThreads() { executor.shutdownNow(); }
232
233    /**
234     * Parses and Vectorizes HTML from a {@code BufferedReader} source.
235     * Spawns a <I>monitor-thread</I> that stops the download if a 
236     * certain, user-specified, time-limit is exceeded.
237     * @param timeout <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_TIMEOUT>
238     * @param unit <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_UNIT>
239     * @param br <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_BR>
240     * @param eliminateHTMLTags <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_ELIM_HT>
241     * @param startTag <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_START_TAG>
242     * @param endTag <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_END_TAG>
243     * @param rawHTMLFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RAW_HTML>
244     * @param matchesFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_MATCHES_F>
245     * @param justTextFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_JUST_TEXT>
246     * @return <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RETURN>
247     * @throws ScrapeException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_SCEX2>
248     * @throws IOException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IOEX>
249     * @throws InterruptedException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IEX>
250     * @throws RejectedExecutionException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_REEX>
251     */
252    public static Vector<HTMLNode> getPageTokens(
253            long timeout, TimeUnit unit,
254            BufferedReader br, boolean eliminateHTMLTags,
255            String startTag, String endTag,
256            String rawHTMLFile, String matchesFile, String justTextFile
257        )
258        throws IOException, InterruptedException
259    {
260        Callable<Vector<HTMLNode>> threadDownloader = new Callable<Vector<HTMLNode>>()
261        {
262            public Vector<HTMLNode> call() throws Exception
263            {
264                return parser.parse(
265                    Scrape.getHTML(br, startTag, endTag),
266                    eliminateHTMLTags, rawHTMLFile, matchesFile, justTextFile
267                );
268            }
269        };
270
271        lock.lock();
272        Future<Vector<HTMLNode>> future = executor.submit(threadDownloader);
273        lock.unlock();
274
275        try
276            { return future.get(timeout, unit); }
277
278        catch (TimeoutException e) { return null; }
279
280        catch (ExecutionException e)
281        {
282            Throwable originalException = e.getCause();
283            if (originalException == null) throw new RejectedExecutionException(
284                "An Execution Exception was thrown, but it did provide a cause throwable " +
285                "(e.getCause() returned null).  See this exception's getCause() method to " +
286                "view the ExecutionException that has occurred.",
287                e
288            );
289
290            if (originalException instanceof IOException)
291                throw (IOException) originalException;
292
293            if (originalException instanceof RuntimeException)
294                throw (RuntimeException) originalException;
295
296            throw new RejectedExecutionException(
297                "An Execution Exception occurred, but it was neither a RuntimeException, " +
298                "nor IOException.  See this exception's getCause() method to view the " +
299                "underlying error that has occurred.", originalException
300            );
301        }
302    }
303
304    /**
305     * Parses and Vectorizes HTML from a {@code BufferedReader} source.
306     * Spawns a <I>monitor-thread</I> that stops the download if a 
307     * certain, user-specified, time-limit is exceeded.
308     * @param timeout <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_TIMEOUT>
309     * @param unit <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_UNIT>
310     * @param br <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_BR>
311     * @param eliminateHTMLTags <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_ELIM_HT>
312     * @param startLineNum <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_START_LN>
313     * @param endLineNum <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_END_LN>
314     * @param rawHTMLFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RAW_HTML>
315     * @param matchesFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_MATCHES_F>
316     * @param justTextFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_JUST_TEXT>
317     * @return <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RETURN>
318     * @throws IllegalArgumentException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IAEX>
319     * @throws ScrapeException  <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_SCEX1>
320     * @throws IOException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IOEX>
321     * @throws InterruptedException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IEX>
322     * @throws RejectedExecutionException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_REEX>
323     */
324    public static Vector<HTMLNode> getPageTokens(
325            long timeout, TimeUnit unit,
326            BufferedReader br, boolean eliminateHTMLTags,
327            int startLineNum, int endLineNum,
328            String rawHTMLFile, String matchesFile, String justTextFile
329        )
330        throws IOException, InterruptedException
331    {
332        Callable<Vector<HTMLNode>> threadDownloader = new Callable<Vector<HTMLNode>>()
333        {
334            public Vector<HTMLNode> call() throws Exception
335            {
336                return parser.parse(
337                    Scrape.getHTML(br, startLineNum, endLineNum),
338                    eliminateHTMLTags, rawHTMLFile, matchesFile, justTextFile
339                );
340            }
341        };
342
343        lock.lock();
344        Future<Vector<HTMLNode>> future = executor.submit(threadDownloader);
345        lock.unlock();
346
347        try
348            { return future.get(timeout, unit); }
349
350        catch (TimeoutException e) { return null; }
351
352        catch (ExecutionException e)
353        {
354            Throwable originalException = e.getCause();
355
356            if (originalException == null) throw new RejectedExecutionException(
357                "An Execution Exception was thrown, but it did provide a cause throwable " +
358                "(e.getCause() returned null).  See this exception's getCause() method to " +
359                "view the ExecutionException has that occurred.",
360                e
361            );
362
363            if (originalException instanceof IOException)
364                throw (IOException) originalException;
365
366            if (originalException instanceof RuntimeException)
367                throw (RuntimeException) originalException;
368
369            throw new RejectedExecutionException(
370                "An Execution Exception occurred, but it was neither a RuntimeException, nor " +
371                "IOException.  See this exception's getCause() method to view the underlying " +
372                "error that has occurred.", originalException
373            );
374        }
375    }
376
377
378    // ********************************************************************************************
379    // ********************************************************************************************
380    // Receives a java.net.URL for the HTML Source parameter -- that could Timeout/Hang
381    // ********************************************************************************************
382    // ********************************************************************************************
383
384
385    // It must be opened within the Multi-Threaded "Timeout" code (and therefore requires a second
386    // version of these two methods - where Scrape.openConn(url) is *inside* the monitored
387    // downloading thread.
388    
389    /**
390     * Parses and Vectorizes HTML from a URL source.
391     * Spawns a <I>monitor-thread</I> that stops the download if a certain, user-specified,
392     * time-limit is exceeded.
393     * @param timeout <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_TIMEOUT>
394     * @param unit <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_UNIT>
395     * @param url <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_URL>
396     * @param eliminateHTMLTags <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_ELIM_HT>
397     * @param startTag <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_START_TAG>
398     * @param endTag <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_END_TAG>
399     * @param rawHTMLFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RAW_HTML>
400     * @param matchesFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_MATCHES_F>
401     * @param justTextFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_JUST_TEXT>
402     * @return <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RETURN>
403     * @throws ScrapeException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_SCEX2>
404     * @throws IOException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IOEX>
405     * @throws InterruptedException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IEX>
406     * @throws RejectedExecutionException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_REEX>
407     */
408    public static Vector<HTMLNode> getPageTokens(
409            long timeout, TimeUnit unit,
410            URL url, boolean eliminateHTMLTags,
411            String startTag, String endTag,
412            String rawHTMLFile, String matchesFile, String justTextFile
413        )
414        throws IOException, InterruptedException
415    {
416        Callable<Vector<HTMLNode>> threadDownloader = new Callable<Vector<HTMLNode>>()
417        {
418            public Vector<HTMLNode> call() throws Exception
419            { 
420                return parser.parse(
421                    Scrape.getHTML(Scrape.openConn(url), startTag, endTag),
422                    eliminateHTMLTags, rawHTMLFile, matchesFile, justTextFile
423                );
424            }
425        };
426
427        lock.lock();
428        Future<Vector<HTMLNode>> future = executor.submit(threadDownloader);
429        lock.unlock();
430
431        try
432            { return future.get(timeout, unit); }
433
434        catch (TimeoutException e) { return null; }
435
436        catch (ExecutionException e)
437        {
438            Throwable originalException = e.getCause();
439
440            if (originalException == null) throw new RejectedExecutionException(
441                "An Execution Exception was thrown, but it did provide a cause throwable " +
442                "(e.getCause() returned null).  See this exception's getCause() method to " +
443                "view the ExecutionException that has occurred.", e
444            );
445
446            if (originalException instanceof IOException)
447                throw (IOException) originalException;
448
449            if (originalException instanceof RuntimeException)
450                throw (RuntimeException) originalException;
451
452            throw new RejectedExecutionException(
453                "An Execution Exception occurred, but it was neither a RuntimeException, " +
454                "nor IOException.  See this exception's getCause() method to view the " +
455                "underlying error that has occurred.", originalException
456            );
457        }
458    }
459
460    
461    /**
462     * Parses and Vectorizes HTML from a URL source.
463     * Spawns a <I>monitor-thread</I> that stops the download if a certain, user-specified,
464     * time-limit is exceeded.
465     * @param timeout <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_TIMEOUT>
466     * @param unit <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_UNIT>
467     * @param url <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_URL>
468     * @param eliminateHTMLTags <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_ELIM_HT>
469     * @param startLineNum <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_START_LN>
470     * @param endLineNum <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_END_LN>
471     * @param rawHTMLFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RAW_HTML>
472     * @param matchesFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_MATCHES_F>
473     * @param justTextFile <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_JUST_TEXT>
474     * @return <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_RETURN>
475     * @throws IllegalArgumentException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IAEX>
476     * @throws ScrapeException  <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_SCEX1>
477     * @throws IOException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IOEX>
478     * @throws InterruptedException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_IEX>
479     * @throws RejectedExecutionException <EMBED CLASS='external-html' DATA-FILE-ID=HTML_PAGE_REEX>
480     */
481    public static Vector<HTMLNode> getPageTokens(
482            long timeout, TimeUnit unit,
483            URL url, boolean eliminateHTMLTags,
484            int startLineNum, int endLineNum,
485            String rawHTMLFile, String matchesFile, String justTextFile
486        )
487        throws IOException, InterruptedException
488    {
489        Callable<Vector<HTMLNode>> threadDownloader = new Callable<Vector<HTMLNode>>()
490        {
491            public Vector<HTMLNode> call() throws Exception
492            { 
493                return parser.parse(
494                    Scrape.getHTML(Scrape.openConn(url), startLineNum, endLineNum),
495                    eliminateHTMLTags, rawHTMLFile, matchesFile, justTextFile
496                );
497            }
498        };
499
500        lock.lock();
501        Future<Vector<HTMLNode>> future = executor.submit(threadDownloader);
502        lock.unlock();
503
504        try
505            { return future.get(timeout, unit); }
506
507        catch (TimeoutException e) { return null; }
508
509        catch (ExecutionException e)
510        {
511            Throwable originalException = e.getCause();
512    
513            if (originalException == null) throw new RejectedExecutionException(
514                "An Execution Exception was thrown, but it did provide a cause throwable " +
515                "(e.getCause() returned null).  See this exception's getCause() method to " +
516                "view the ExecutionException has that occurred.",
517                e
518            );
519
520            if (originalException instanceof IOException)
521                throw (IOException) originalException;
522
523            if (originalException instanceof RuntimeException)
524                throw (RuntimeException) originalException;
525
526            throw new RejectedExecutionException(
527                "An Execution Exception occurred, but it was neither a RuntimeException, nor " +
528                "IOException.  See this exception's getCause() method to view the underlying " +
529                "error that has occurred.", originalException
530            );
531        }
532    }
533}