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