@@ -0,0 +1,2498 @@
+package com.ciscospark;%0A%0Aimport java.io.IOException;%0Aimport java.io.InputStream;%0Aimport java.net.HttpURLConnection;%0Aimport java.net.URL;%0Aimport java.util.Collection;%0Aimport java.util.LinkedHashMap;%0Aimport java.util.Map;%0Aimport java.util.NoSuchElementException;%0Aimport java.util.function.Function;%0Aimport java.util.regex.Matcher;%0Aimport java.util.regex.Pattern;%0A%0A/**%0A * Created on 11/28/15.%0A */%0Apublic class LinkedResponse%3CT%3E %7B%0A    private final Client client;%0A    private Client.Response response;%0A    private final Function%3CInputStream, T%3E bodyCreator;%0A    private final Map%3CString,URL%3E urls = new LinkedHashMap%3C%3E();%0A%0A    LinkedResponse(Client client, URL url, Function%3CInputStream, T%3E bodyCreator) throws IOException %7B%0A        this.client = client;%0A        this.bodyCreator = bodyCreator;%0A        followUrl(url);%0A    %7D%0A%0A    private void followUrl(URL url) %7B%0A        try %7B%0A            this.response = client.request(url, %22GET%22, null);%0A            int responseCode = this.response.connection.getResponseCode();%0A            if (!isOk(responseCode)) %7B%0A                throw new IOException(%22bad response code: %22 + responseCode);%0A            %7D%0A            parseLinks(response.connection);%0A        %7D catch (IOException e) %7B%0A            throw new SparkException(e);%0A        %7D%0A    %7D%0A%0A    private static final Pattern linkPattern = Pattern.compile(%22%5C%5Cs*%3C(%5C%5CS+)%3E%5C%5Cs*;%5C%5Cs*rel=%5C%22(%5C%5CS+)%5C%22,?%22);%0A%0A    private void parseLinks(HttpURLConnection connection) throws IOException %7B%0A        urls.clear();%0A        String link = connection.getHeaderField(%22Link%22);%0A        if (link != null && !%22%22.equals(link)) %7B%0A            Matcher matcher = linkPattern.matcher(link);%0A            while (matcher.find()) %7B%0A                String url = matcher.group(1);%0A                String foundRel = matcher.group(2);%0A                urls.put(foundRel, new URL(url));%0A            %7D%0A        %7D%0A    %7D%0A%0A    public Collection%3CString%3E getLinks() %7B%0A        return urls.keySet();%0A    %7D%0A%0A    public boolean hasLink(String rel) %7B%0A        return urls.containsKey(rel);%0A    %7D%0A%0A    public T consumeBody() %7B%0A        return bodyCreator.apply(response.inputStream);%0A    %7D%0A%0A    public void followLink(String rel) %7B%0A        if (hasLink(rel)) %7B%0A            followUrl(urls.get(rel));%0A        %7D else %7B%0A            throw new NoSuchElementException();%0A        %7D%0A    %7D%0A%0A    private boolean isOk(int responseCode) %7B%0A        return (responseCode %3E= 200 && responseCode %3C 400);%0A    %7D%0A%0A    public URL getLink(String rel) %7B%0A        return urls.get(rel);%0A    %7D%0A%7D%0A

introduce parameterized test data for pagination [COLLAB-222] [COLLAB-224] [COLLAB-173] [COLLAB-144]