class ExtractorURI extends Extractor {

    @SuppressWarnings("unused")
    private static final long serialVersionUID = 3L;

    private static Logger LOGGER =
        Logger.getLogger(ExtractorURI.class.getName());

    protected static final String ABS_HTTP_URI_PATTERN = "^https?://[^\\s<>]*$";

    /**
     * Constructor
     */
    public ExtractorURI() {
    }

    
    @Override
    protected boolean shouldProcess(CrawlURI uri) {
        return true;
    }
    
    /**
     * Perform usual extraction on a CrawlURI
     * 
     * @param curi Crawl URI to process.
     */
    @Override
    public void extract(CrawlURI curi) {
        for (CrawlURI link : curi.getOutLinks()) {
            extractLink(curi, link);
        }
    }

    /**
     * Consider a single Link for internal URIs
     * 
     * @param curi CrawlURI to add discoveries to 
     * @param wref Link to examine for internal URIs
     */
    protected void extractLink(CrawlURI curi, CrawlURI wref) {<FILL_FUNCTION_BODY>}

    /**
     * Look for URIs inside the supplied UURI.
     * 
     * Static for ease of testing or outside use. 
     * 
     * @param source UURI to example
     * @return List of discovered String URIs.
     */
    protected static List<String> extractQueryStringLinks(UURI source) {
        List<String> results = new ArrayList<String>(); 
        String decodedQuery;
        try {
            decodedQuery = source.getQuery();
        } catch (URIException e1) {
            // shouldn't happen
            return results;
        }
        if(decodedQuery==null) {
            return results;
        }
        // check if full query-string appears to be http(s) URI
        Matcher m = TextUtils.getMatcher(ABS_HTTP_URI_PATTERN,decodedQuery);
        if(m.matches()) {
            TextUtils.recycleMatcher(m);
            results.add(decodedQuery);
        }
        // split into params, see if any param value is http(s) URI
        String rawQuery = new String(source.getRawQuery());
        String[] params = rawQuery.split("&");
        for (String param : params) {
            String[] keyVal = param.split("=");
            if(keyVal.length==2) {
                String candidate;
                try {
                    candidate = LaxURLCodec.DEFAULT.decode(keyVal[1]);
                } catch (DecoderException e) {
                    continue;
                }
                // TODO: use other non-UTF8 codecs when appropriate
                m.reset(candidate);
                if(m.matches()) {
                    results.add(candidate);
                }
            }
        }
        return results;
    }
}

        UURI source = null;
        try {
            source = UURIFactory.getInstance(wref.getURI());
        } catch (URIException e) {
            LOGGER.log(Level.FINE,"bad URI",e);
        }
        if(source == null) {
            // shouldn't happen
            return; 
        }
        List<String> found = extractQueryStringLinks(source);
        for (String uri : found) {
            try {
                UURI dest = UURIFactory.getInstance(uri);
                LinkContext lc = LinkContext.SPECULATIVE_MISC;
                Hop hop = Hop.SPECULATIVE;
                addOutlink(curi, dest, lc, hop);
                numberOfLinksExtracted.incrementAndGet();
            } catch (URIException e) {
                LOGGER.log(Level.FINE, "bad URI", e);
            }
        }
        // TODO: consider path URIs too
        
    
<methods>public non-sealed void <init>() ,public static void add(org.archive.modules.CrawlURI, int, java.lang.String, org.archive.modules.extractor.LinkContext, org.archive.modules.extractor.Hop) throws URIException,public static org.archive.modules.CrawlURI addRelativeToBase(org.archive.modules.CrawlURI, int, java.lang.CharSequence, org.archive.modules.extractor.LinkContext, org.archive.modules.extractor.Hop) throws URIException,public static org.archive.modules.CrawlURI addRelativeToVia(org.archive.modules.CrawlURI, int, java.lang.String, org.archive.modules.extractor.LinkContext, org.archive.modules.extractor.Hop) throws URIException,public org.archive.modules.extractor.ExtractorParameters getExtractorParameters() ,public org.archive.modules.extractor.UriErrorLoggerModule getLoggerModule() ,public void logUriError(URIException, org.archive.net.UURI, java.lang.CharSequence) ,public java.lang.String report() ,public void setExtractorParameters(org.archive.modules.extractor.ExtractorParameters) ,public void setLoggerModule(org.archive.modules.extractor.UriErrorLoggerModule) <variables>public static final org.archive.modules.extractor.ExtractorParameters DEFAULT_PARAMETERS,private static final java.util.logging.Logger LOGGER,protected transient org.archive.modules.extractor.ExtractorParameters extractorParameters,private static final java.util.logging.Logger logger,protected transient org.archive.modules.extractor.UriErrorLoggerModule loggerModule,protected java.util.concurrent.atomic.AtomicLong numberOfLinksExtracted