/****************************************************************************** * Copyright (c) 2011 GitHub Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Kevin Sawicki (GitHub Inc.) - initial API and implementation *****************************************************************************/ package org.eclipse.egit.github.core.client; import static org.eclipse.egit.github.core.client.IGitHubConstants.PARAM_PAGE; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import org.eclipse.egit.github.core.IResourceProvider; import org.eclipse.egit.github.core.util.UrlUtils; /** * Iterator for getting paged responses. Each call to {@link #next()} will make * a client request for the next page of resources using the URI returned from * the previous request. * * The {@link #hasNext()} method can be used to determine if the last executed * request contained the location of the next page of results. * * This iterator also provides the next and last page numbers as well as the * next and last URIs. * * @param <V> * type of resource being iterated over */ public class PageIterator<V> implements Iterator<Collection<V>>, Iterable<Collection<V>> { /** * Request */ protected final PagedRequest<V> request; /** * Client */ protected final GitHubClient client; /** * Current page number */ protected int nextPage; /** * Last page number */ protected int lastPage; /** * Next uri to be fetched */ protected String next; /** * Last uri to be fetched */ protected String last; /** * Create page iterator * * @param request * @param client */ public PageIterator(PagedRequest<V> request, GitHubClient client) { this.request = request; this.client = client; next = request.getUri(); nextPage = parsePageNumber(next); } /** * Parse page number from uri * * @param uri * @return page number */ protected int parsePageNumber(String uri) { if (uri == null || uri.length() == 0) return -1; final URI parsed; try { parsed = new URI(uri); } catch (URISyntaxException e) { return -1; } final String param = UrlUtils.getParam(parsed, PARAM_PAGE); if (param == null || param.length() == 0) return -1; try { return Integer.parseInt(param); } catch (NumberFormatException nfe) { return -1; } } /** * Get number of next page to be read * * @return next page */ public int getNextPage() { return nextPage; } /** * Get number of last page * * @return page number */ public int getLastPage() { return lastPage; } /** * Get URI of next request * * @return next page uri */ public String getNextUri() { return next; } /** * Get uri of last page * * @return last page uri */ public String getLastUri() { return last; } public boolean hasNext() { return nextPage == 0 || next != null; } public void remove() { throw new UnsupportedOperationException("Remove not supported"); //$NON-NLS-1$ } @SuppressWarnings("unchecked") public Collection<V> next() { if (!hasNext()) throw new NoSuchElementException(); if (next != null) if (nextPage < 1) request.setUri(next); else try { request.setUri(new URL(next).getFile()); } catch (MalformedURLException e) { request.setUri(next); } GitHubResponse response; try { response = client.get(request); } catch (IOException e) { throw new NoSuchPageException(e); } Collection<V> resources = null; Object body = response.getBody(); if (body != null) if (body instanceof Collection) resources = (Collection<V>) body; else if (body instanceof IResourceProvider) resources = ((IResourceProvider<V>) body).getResources(); else resources = (Collection<V>) Collections.singletonList(body); if (resources == null) resources = Collections.emptyList(); nextPage++; next = response.getNext(); nextPage = parsePageNumber(next); last = response.getLast(); lastPage = parsePageNumber(last); return resources; } /** * Get request being executed * * @return request */ public PagedRequest<V> getRequest() { return request; } /** * @return this page iterator */ public Iterator<Collection<V>> iterator() { return this; } }