mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-23 15:50:48 +00:00
180 lines
9.6 KiB
HTML
180 lines
9.6 KiB
HTML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>GitHubPageIterator.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">GitHub API for Java</a> > <a href="index.source.html" class="el_package">org.kohsuke.github</a> > <span class="el_source">GitHubPageIterator.java</span></div><h1>GitHubPageIterator.java</h1><pre class="source lang-java linenums">package org.kohsuke.github;
|
|
|
|
import java.io.IOException;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.util.Iterator;
|
|
import java.util.NoSuchElementException;
|
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
/**
|
|
* May be used for any item that has pagination information. Iterates over paginated {@link T} objects (not the items
|
|
* inside the page). Also exposes {@link #finalResponse()} to allow getting a full {@link GitHubResponse<T>} after
|
|
* iterating completes.
|
|
*
|
|
* Works for array responses, also works for search results which are single instances with an array of items inside.
|
|
*
|
|
* This class is not thread-safe. Any one instance should only be called from a single thread.
|
|
*
|
|
* @param <T>
|
|
* type of each page (not the items in the page).
|
|
*/
|
|
<span class="pc bpc" id="L23" title="1 of 2 branches missed.">class GitHubPageIterator<T> implements Iterator<T> {</span>
|
|
|
|
private final GitHubClient client;
|
|
private final Class<T> type;
|
|
|
|
/**
|
|
* The page that will be returned when {@link #next()} is called.
|
|
*
|
|
* <p>
|
|
* Will be {@code null} after {@link #next()} is called.
|
|
* </p>
|
|
* <p>
|
|
* Will not be {@code null} after {@link #fetch()} is called if a new page was fetched.
|
|
* </p>
|
|
*/
|
|
private T next;
|
|
|
|
/**
|
|
* The request that will be sent when to get a new response page if {@link #next} is {@code null}. Will be
|
|
* {@code null} when there are no more pages to fetch.
|
|
*/
|
|
private GitHubRequest nextRequest;
|
|
|
|
/**
|
|
* When done iterating over pages, it is on rare occasions useful to be able to get information from the final
|
|
* response that was retrieved.
|
|
*/
|
|
<span class="fc" id="L50"> private GitHubResponse<T> finalResponse = null;</span>
|
|
|
|
<span class="fc" id="L52"> private GitHubPageIterator(GitHubClient client, Class<T> type, GitHubRequest request) {</span>
|
|
<span class="pc bpc" id="L53" title="1 of 2 branches missed."> if (!"GET".equals(request.method())) {</span>
|
|
<span class="nc" id="L54"> throw new IllegalStateException("Request method \"GET\" is required for page iterator.");</span>
|
|
}
|
|
|
|
<span class="fc" id="L57"> this.client = client;</span>
|
|
<span class="fc" id="L58"> this.type = type;</span>
|
|
<span class="fc" id="L59"> this.nextRequest = request;</span>
|
|
<span class="fc" id="L60"> }</span>
|
|
|
|
/**
|
|
* Loads paginated resources.
|
|
*
|
|
* @param client
|
|
* the {@link GitHubClient} from which to request responses
|
|
* @param type
|
|
* type of each page (not the items in the page).
|
|
* @param <T>
|
|
* type of each page (not the items in the page).
|
|
* @return iterator
|
|
*/
|
|
static <T> GitHubPageIterator<T> create(GitHubClient client, Class<T> type, GitHubRequest request, int pageSize) {
|
|
|
|
try {
|
|
<span class="fc bfc" id="L76" title="All 2 branches covered."> if (pageSize > 0) {</span>
|
|
<span class="fc" id="L77"> GitHubRequest.Builder<?> builder = request.toBuilder().with("per_page", pageSize);</span>
|
|
<span class="fc" id="L78"> request = builder.build();</span>
|
|
}
|
|
|
|
<span class="fc" id="L81"> return new GitHubPageIterator<>(client, type, request);</span>
|
|
<span class="nc" id="L82"> } catch (MalformedURLException e) {</span>
|
|
<span class="nc" id="L83"> throw new GHException("Unable to build GitHub API URL", e);</span>
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public boolean hasNext() {
|
|
<span class="fc" id="L91"> fetch();</span>
|
|
<span class="fc bfc" id="L92" title="All 2 branches covered."> return next != null;</span>
|
|
}
|
|
|
|
/**
|
|
* Gets the next page.
|
|
*
|
|
* @return the next page.
|
|
*/
|
|
@Nonnull
|
|
public T next() {
|
|
<span class="fc" id="L102"> fetch();</span>
|
|
<span class="fc" id="L103"> T result = next;</span>
|
|
<span class="pc bpc" id="L104" title="1 of 2 branches missed."> if (result == null)</span>
|
|
<span class="nc" id="L105"> throw new NoSuchElementException();</span>
|
|
// If this is the last page, keep the response
|
|
<span class="fc" id="L107"> next = null;</span>
|
|
<span class="fc" id="L108"> return result;</span>
|
|
}
|
|
|
|
/**
|
|
* On rare occasions the final response from iterating is needed.
|
|
*
|
|
* @return the final response of the iterator.
|
|
*/
|
|
public GitHubResponse<T> finalResponse() {
|
|
<span class="pc bpc" id="L117" title="1 of 2 branches missed."> if (hasNext()) {</span>
|
|
<span class="nc" id="L118"> throw new GHException("Final response is not available until after iterator is done.");</span>
|
|
}
|
|
<span class="fc" id="L120"> return finalResponse;</span>
|
|
}
|
|
|
|
/**
|
|
* Fetch is called at the start of {@link #hasNext()} or {@link #next()} to fetch another page of data if it is
|
|
* needed.
|
|
* <p>
|
|
* If {@link #next} is not {@code null}, no further action is needed. If {@link #next} is {@code null} and
|
|
* {@link #nextRequest} is {@code null}, there are no more pages to fetch.
|
|
* </p>
|
|
* <p>
|
|
* Otherwise, a new response page is fetched using {@link #nextRequest}. The response is then checked to see if
|
|
* there is a page after it and {@link #nextRequest} is updated to point to it. If there are no pages available
|
|
* after the current response, {@link #nextRequest} is set to {@code null}.
|
|
* </p>
|
|
*/
|
|
private void fetch() {
|
|
<span class="fc bfc" id="L137" title="All 2 branches covered."> if (next != null)</span>
|
|
<span class="fc" id="L138"> return; // already fetched</span>
|
|
<span class="fc bfc" id="L139" title="All 2 branches covered."> if (nextRequest == null)</span>
|
|
<span class="fc" id="L140"> return; // no more data to fetch</span>
|
|
|
|
<span class="fc" id="L142"> URL url = nextRequest.url();</span>
|
|
try {
|
|
<span class="fc" id="L144"> GitHubResponse<T> nextResponse = client.sendRequest(nextRequest,</span>
|
|
<span class="fc" id="L145"> (responseInfo) -> GitHubResponse.parseBody(responseInfo, type));</span>
|
|
<span class="pc bpc" id="L146" title="2 of 4 branches missed."> assert nextResponse.body() != null;</span>
|
|
<span class="fc" id="L147"> next = nextResponse.body();</span>
|
|
<span class="fc" id="L148"> nextRequest = findNextURL(nextResponse);</span>
|
|
<span class="fc bfc" id="L149" title="All 2 branches covered."> if (nextRequest == null) {</span>
|
|
<span class="fc" id="L150"> finalResponse = nextResponse;</span>
|
|
}
|
|
<span class="fc" id="L152"> } catch (IOException e) {</span>
|
|
// Iterators do not throw IOExceptions, so we wrap any IOException
|
|
// in a runtime GHException to bubble out if needed.
|
|
<span class="fc" id="L155"> throw new GHException("Failed to retrieve " + url, e);</span>
|
|
<span class="fc" id="L156"> }</span>
|
|
<span class="fc" id="L157"> }</span>
|
|
|
|
/**
|
|
* Locate the next page from the pagination "Link" tag.
|
|
*/
|
|
private GitHubRequest findNextURL(GitHubResponse<T> nextResponse) throws MalformedURLException {
|
|
<span class="fc" id="L163"> GitHubRequest result = null;</span>
|
|
<span class="fc" id="L164"> String link = nextResponse.headerField("Link");</span>
|
|
<span class="fc bfc" id="L165" title="All 2 branches covered."> if (link != null) {</span>
|
|
<span class="fc bfc" id="L166" title="All 2 branches covered."> for (String token : link.split(", ")) {</span>
|
|
<span class="fc bfc" id="L167" title="All 2 branches covered."> if (token.endsWith("rel=\"next\"")) {</span>
|
|
// found the next page. This should look something like
|
|
// <https://api.github.com/repos?page=3&per_page=100>; rel="next"
|
|
<span class="fc" id="L170"> int idx = token.indexOf('>');</span>
|
|
<span class="fc" id="L171"> result = nextResponse.request().toBuilder().setRawUrlPath(token.substring(1, idx)).build();</span>
|
|
<span class="fc" id="L172"> break;</span>
|
|
}
|
|
}
|
|
}
|
|
<span class="fc" id="L176"> return result;</span>
|
|
}
|
|
|
|
}
|
|
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html> |