Coverage Report - com.jcabi.github.RtSearchPagination
 
Classes in this File Line Coverage Branch Coverage Complexity
RtSearchPagination
91%
11/12
0%
0/4
1.414
RtSearchPagination$Hidden
47%
11/23
N/A
1.414
RtSearchPagination$SearchRequest
33%
4/12
N/A
1.414
RtSearchPagination$SearchURI
0%
0/13
0%
0/12
1.414
 
 1  2
 /**
 2  
  * Copyright (c) 2013-2017, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.github;
 31  
 
 32  
 import com.jcabi.aspects.Immutable;
 33  
 import com.jcabi.http.Request;
 34  
 import com.jcabi.http.RequestBody;
 35  
 import com.jcabi.http.RequestURI;
 36  
 import com.jcabi.http.Response;
 37  
 import com.jcabi.http.Wire;
 38  
 import java.io.IOException;
 39  
 import java.io.InputStream;
 40  
 import java.io.StringReader;
 41  
 import java.io.UnsupportedEncodingException;
 42  
 import java.lang.reflect.InvocationTargetException;
 43  
 import java.net.URI;
 44  
 import java.util.Iterator;
 45  
 import java.util.List;
 46  
 import java.util.Map;
 47  
 import javax.json.Json;
 48  
 import javax.json.JsonObject;
 49  
 import lombok.EqualsAndHashCode;
 50  
 
 51  
 /**
 52  
  * Github search pagination.
 53  
  *
 54  
  * @author Alexander Sinyagin (sinyagin.alexander@gmail.com)
 55  
  * @version $Id: f85f466e4c8f61e81d02db53d790c233220016b6 $
 56  
  * @param <T> Type of iterable objects
 57  
  */
 58  
 @Immutable
 59  0
 @EqualsAndHashCode
 60  
 @SuppressWarnings("PMD.TooManyMethods")
 61  
 final class RtSearchPagination<T> implements Iterable<T> {
 62  
 
 63  
     /**
 64  
      * Search request.
 65  
      */
 66  
     private final transient Request request;
 67  
 
 68  
     /**
 69  
      * Pagination mapping.
 70  
      */
 71  
     private final transient RtValuePagination.Mapping<T, JsonObject> mapping;
 72  
 
 73  
     /**
 74  
      * Ctor.
 75  
      * @param req RESTful API entry point
 76  
      * @param path Search path
 77  
      * @param keywords Search keywords
 78  
      * @param sort Sort field
 79  
      * @param order Sort order
 80  
      * @param mppng Pagination mapping
 81  
      * @checkstyle ParameterNumber (4 lines)
 82  
      */
 83  
     RtSearchPagination(final Request req, final String path,
 84  
         final String keywords, final String sort, final String order,
 85  5
         final RtValuePagination.Mapping<T, JsonObject> mppng) {
 86  5
         this.request = req.uri().path(path)
 87  5
             .queryParam("q", keywords)
 88  5
             .queryParam("sort", sort)
 89  5
             .queryParam("order", order)
 90  5
             .back();
 91  5
         this.mapping = mppng;
 92  5
     }
 93  
 
 94  
     @Override
 95  
     public Iterator<T> iterator() {
 96  10
         return new RtPagination<T>(
 97  
             new RtSearchPagination.SearchRequest(this.request),
 98  
             this.mapping
 99  5
         ).iterator();
 100  
     }
 101  
 
 102  
     /**
 103  
      * Request which hides everything but items.
 104  
      */
 105  
     @SuppressWarnings({ "PMD.TooManyMethods", "PMD.CyclomaticComplexity" })
 106  
     private static final class SearchRequest implements Request {
 107  
         /**
 108  
          * Inner request.
 109  
          */
 110  
         private final transient Request request;
 111  
         /**
 112  
          * Ctor.
 113  
          * @param req Request to wrap
 114  
          */
 115  5
         SearchRequest(final Request req) {
 116  5
             this.request = req;
 117  5
         }
 118  
         @Override
 119  
         public RequestURI uri() {
 120  0
             return new SearchURI(this.request.uri());
 121  
         }
 122  
         @Override
 123  
         public RequestBody body() {
 124  0
             return this.request.body();
 125  
         }
 126  
         @Override
 127  
         public Request header(final String name, final Object value) {
 128  0
             return new SearchRequest(this.request.header(name, value));
 129  
         }
 130  
         @Override
 131  
         public Request reset(final String name) {
 132  0
             return new SearchRequest(this.request.reset(name));
 133  
         }
 134  
         @Override
 135  
         public Request method(final String method) {
 136  0
             return new SearchRequest(this.request.method(method));
 137  
         }
 138  
         @Override
 139  
         public Request timeout(final int first, final int second) {
 140  0
             return new SearchRequest(this.request);
 141  
         }
 142  
 
 143  
         /**
 144  
          * Hide everything from the body but items.
 145  
          * @return Response
 146  
          * @throws IOException If any I/O problem occurs
 147  
          */
 148  
         @Override
 149  
         public Response fetch() throws IOException {
 150  5
             return new RtSearchPagination.Hidden(this.request.fetch());
 151  
         }
 152  
         @Override
 153  
         public Response fetch(final InputStream stream) throws IOException {
 154  0
             return new RtSearchPagination.Hidden(this.request.fetch(stream));
 155  
         }
 156  
         @Override
 157  
         public <T extends Wire> Request through(final Class<T> type,
 158  
             final Object... args) {
 159  0
             return new SearchRequest(this.request.through(type, args));
 160  
         }
 161  
     }
 162  
 
 163  
     /**
 164  
      * Response to return.
 165  
      */
 166  
     @Immutable
 167  
     private static final class Hidden implements Response {
 168  
         /**
 169  
          * Original response.
 170  
          */
 171  
         private final transient Response response;
 172  
         /**
 173  
          * Ctor.
 174  
          * @param resp Response
 175  
          */
 176  5
         Hidden(final Response resp) {
 177  5
             this.response = resp;
 178  5
         }
 179  
         @Override
 180  
         public Request back() {
 181  0
             return new SearchRequest(this.response.back());
 182  
         }
 183  
         @Override
 184  
         public int status() {
 185  5
             return this.response.status();
 186  
         }
 187  
         @Override
 188  
         public String reason() {
 189  0
             return this.response.reason();
 190  
         }
 191  
         @Override
 192  
         public Map<String, List<String>> headers() {
 193  5
             return this.response.headers();
 194  
         }
 195  
         @Override
 196  
         public String body() {
 197  10
             return Json.createReader(new StringReader(this.response.body()))
 198  5
                 .readObject().getJsonArray("items").toString();
 199  
         }
 200  
         @Override
 201  
         public byte[] binary() {
 202  
             try {
 203  5
                 return this.body().getBytes("UTF-8");
 204  0
             } catch (final UnsupportedEncodingException ex) {
 205  0
                 throw new IllegalStateException(ex);
 206  
             }
 207  
         }
 208  
         // @checkstyle MethodName (4 lines)
 209  
         @Override
 210  
         @SuppressWarnings("PMD.ShortMethodName")
 211  
         public <T extends Response> T as(final Class<T> type) {
 212  
             try {
 213  30
                 return type.getDeclaredConstructor(Response.class)
 214  15
                     .newInstance(this);
 215  0
             } catch (final InstantiationException ex) {
 216  0
                 throw new IllegalStateException(ex);
 217  0
             } catch (final IllegalAccessException ex) {
 218  0
                 throw new IllegalStateException(ex);
 219  0
             } catch (final InvocationTargetException ex) {
 220  0
                 throw new IllegalStateException(ex);
 221  0
             } catch (final NoSuchMethodException ex) {
 222  0
                 throw new IllegalStateException(ex);
 223  
             }
 224  
         }
 225  
     }
 226  
 
 227  
     /**
 228  
      * Wrapper of RequestURI that returns {@link SearchRequest}.
 229  
      */
 230  
     @Immutable
 231  0
     @EqualsAndHashCode(of = "address")
 232  
     private static final class SearchURI implements RequestURI {
 233  
         /**
 234  
          * Underlying address.
 235  
          */
 236  
         private final transient RequestURI address;
 237  
         /**
 238  
          * Ctor.
 239  
          * @param uri The URI
 240  
          */
 241  0
         public SearchURI(final RequestURI uri) {
 242  0
             this.address = uri;
 243  0
         }
 244  
         @Override
 245  
         public Request back() {
 246  0
             return new SearchRequest(this.address.back());
 247  
         }
 248  
         @Override
 249  
         public URI get() {
 250  0
             return this.address.get();
 251  
         }
 252  
         @Override
 253  
         public RequestURI set(final URI uri) {
 254  0
             return new SearchURI(this.address.set(uri));
 255  
         }
 256  
         @Override
 257  
         public RequestURI queryParam(final String name, final Object value) {
 258  0
             return new SearchURI(this.address.queryParam(name, value));
 259  
         }
 260  
         @Override
 261  
         public RequestURI queryParams(final Map<String, String> map) {
 262  0
             return new SearchURI(this.address.queryParams(map));
 263  
         }
 264  
         @Override
 265  
         public RequestURI path(final String segment) {
 266  0
             return new SearchURI(this.address.path(segment));
 267  
         }
 268  
         @Override
 269  
         public RequestURI userInfo(final String info) {
 270  0
             return new SearchURI(this.address.userInfo(info));
 271  
         }
 272  
         @Override
 273  
         public RequestURI port(final int num) {
 274  0
             return new SearchURI(this.address.port(num));
 275  
         }
 276  
     }
 277  
 }