7f6c296d98e8403e18070886753e8970bb921dfc
[controller.git] / opendaylight / networkconfiguration / neutron / northbound / src / main / java / org / opendaylight / controller / networkconfig / neutron / northbound / PaginatedRequestFactory.java
1 /*
2  * Copyright (C) 2014 Red Hat, Inc.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  *
8  *  Authors : Dave Tucker
9  */
10
11 package org.opendaylight.controller.networkconfig.neutron.northbound;
12
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.List;
17 import javax.ws.rs.core.UriInfo;
18 import org.opendaylight.controller.networkconfig.neutron.INeutronObject;
19 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
20 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
21 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
22 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
23 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
24
25 public class PaginatedRequestFactory {
26     private static final Comparator<INeutronObject> NEUTRON_OBJECT_COMPARATOR = new Comparator<INeutronObject>() {
27         @Override
28         public int compare(INeutronObject o1, INeutronObject o2) {
29             return o1.getID().compareTo(o2.getID());
30         }
31     };
32
33     public static class PaginationResults<T extends INeutronObject> {
34         List<T> collection;
35         List<NeutronPageLink> links;
36
37         public PaginationResults(List<T> collection, List<NeutronPageLink> links) {
38             this.collection = collection;
39             this.links = links;
40         }
41     }
42
43     private static final class MarkerObject implements INeutronObject {
44         private final String id;
45
46         MarkerObject(String id) {
47             this.id = id;
48         }
49
50         @Override
51         public String getID() {
52             return id;
53         }
54
55         @Override
56         public void setID(String id) {
57             throw new UnsupportedOperationException("Marker has constant ID");
58         }
59     }
60
61     /*
62      * SuppressWarnings is needed because the compiler does not understand that we
63      * are actually safe here.
64      *
65      * FIXME: the only caller performs a cast back, so this is not actually necessary.
66      */
67     @SuppressWarnings("unchecked")
68     public static <T extends INeutronObject> INeutronRequest<T> createRequest(Integer limit, String marker,
69                                                                            Boolean pageReverse,
70                                                                            UriInfo uriInfo,
71                                                                            List<T> collection,
72                                                                            Class<T> clazz) {
73         PaginationResults<T> results = _paginate(limit, marker, pageReverse, uriInfo, collection);
74
75         if (clazz.equals(NeutronNetwork.class)){
76             return (INeutronRequest<T>) new NeutronNetworkRequest((List<NeutronNetwork>) results.collection, results.links);
77         }
78         if (clazz.equals(NeutronSubnet.class)){
79             return (INeutronRequest<T>) new NeutronSubnetRequest((List<NeutronSubnet>) results.collection, results.links);
80         }
81         if (clazz.equals(NeutronPort.class)){
82             return (INeutronRequest<T>) new NeutronPortRequest((List<NeutronPort>) results.collection, results.links);
83         }
84         return null;
85     }
86
87     private static <T extends INeutronObject> PaginationResults<T> _paginate(Integer limit, String marker, Boolean pageReverse, UriInfo uriInfo, List<T> collection) {
88         List<NeutronPageLink> links = new ArrayList<>();
89         final int startPos;
90         String startMarker;
91         String endMarker;
92         Boolean firstPage = false;
93         Boolean lastPage = false;
94
95         Collections.sort(collection, NEUTRON_OBJECT_COMPARATOR);
96
97         if (marker != null) {
98             int offset = Collections.binarySearch(collection, new MarkerObject(marker), NEUTRON_OBJECT_COMPARATOR);
99             if (offset < 0) {
100                 throw new ResourceNotFoundException("UUID for marker: " + marker + " could not be found");
101             }
102
103             if (!pageReverse) {
104                 startPos = offset + 1;
105             }
106             else {
107                 startPos = offset - limit;
108             }
109         }
110         else {
111             startPos = 0;
112         }
113
114         if (startPos == 0){
115             firstPage = true;
116         }
117
118         if (startPos + limit >= collection.size()) {
119             collection = collection.subList(startPos, collection.size());
120             startMarker = collection.get(0).getID();
121             endMarker = collection.get(collection.size() - 1).getID();
122             lastPage = true;
123         }
124         else if (startPos < 0) {
125             if (startPos + limit > 0) {
126                 collection = collection.subList(0, startPos + limit);
127                 startMarker = collection.get(0).getID();
128                 endMarker = collection.get(collection.size() - 1).getID();
129                 firstPage = true;
130             }
131             else {
132                 throw new BadRequestException("Requested page is out of bounds. Please check the supplied limit and marker");
133             }
134         }
135         else {
136             collection = collection.subList(startPos, startPos + limit);
137             startMarker = collection.get(0).getID();
138             endMarker = collection.get(limit-1).getID();
139         }
140
141         if (!lastPage) {
142             NeutronPageLink next = new NeutronPageLink();
143             next.setRef("next");
144             next.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + endMarker);
145             links.add(next);
146         }
147
148         if (!firstPage) {
149             NeutronPageLink previous = new NeutronPageLink();
150             previous.setRef("previous");
151             previous.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + startMarker + "&page_reverse=True");
152             links.add(previous);
153         }
154
155         return new PaginationResults<T>(collection, links);
156     }
157 }