Google APIs Client Library for C++
|
00001 /* 00002 * \copyright Copyright 2013 Google Inc. All Rights Reserved. 00003 * \license @{ 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 * 00017 * @} 00018 */ 00019 // A service request pager acts as a high level iterator for paging 00020 // through results. Each page involves a round-trip request the the server. 00021 00022 #ifndef APISERVING_CLIENTSCPP_SERVICE_SERVICE_REQUEST_PAGER_H_ 00023 #define APISERVING_CLIENTSCPP_SERVICE_SERVICE_REQUEST_PAGER_H_ 00024 00025 #include "googleapis/base/macros.h" 00026 #include "googleapis/base/scoped_ptr.h" 00027 #include "googleapis/client/transport/http_response.h" 00028 #include "googleapis/client/util/status.h" 00029 #include "googleapis/strings/strcat.h" 00030 #include "googleapis/strings/stringpiece.h" 00031 #include "googleapis/util/status.h" 00032 namespace googleapis { 00033 00034 namespace client { 00035 00036 class ClientServiceRequest; 00037 class HttpRequest; 00038 00039 /* 00040 * Base class for component that pages through REST results. 00041 * @ingroup ClientServiceLayer 00042 * 00043 * This class is abstract requiring ExecuteNextPage to be implemented 00044 * to instruct the pager how to specify (and determine) the next page. 00045 * 00046 * Normally the concrete ServiceRequestPager is used. 00047 */ 00048 class BaseServiceRequestPager { 00049 public: 00050 /* 00051 * Standard constructor. 00052 * 00053 * @param[in] request A reference to a prototype request used to fetch 00054 * the next page. Ownership is retained by the caller. 00055 */ 00056 explicit BaseServiceRequestPager(ClientServiceRequest* request); 00057 00058 /* 00059 * Standard destructor. 00060 */ 00061 virtual ~BaseServiceRequestPager(); 00062 00063 /* 00064 * Returns the current page request. 00065 * 00066 * @return Ownership is retained by this instance. 00067 */ 00068 ClientServiceRequest* request() { return request_; } 00069 00070 /* 00071 * Returns the current page response. 00072 * 00073 * @return Ownership is retained by this instance. 00074 */ 00075 HttpResponse* http_response() { return &http_response_; } 00076 00077 /* 00078 * Determine if this was the last known page. 00079 * @return true if we are done, false if not. 00080 * We might still be done even if false is returned if the end 00081 * was on a page boundary. 00082 */ 00083 bool is_done() const { return done_; } 00084 00085 /* 00086 * Fetch the next page. 00087 * 00088 * @return true if we could fetch another page, false if we are done. 00089 */ 00090 bool NextPage(); 00091 00092 /* 00093 * Resets the pager back to the start. 00094 * 00095 * The next iteration may be different than the previous one depending 00096 * on the backend service. 00097 */ 00098 void Reset(); 00099 00100 protected: 00101 /* 00102 * Does the actual messaging to the service to get the next page. 00103 * 00104 * @return ok or reason for failure. 00105 */ 00106 virtual util::Status ExecuteNextPage() = 0; 00107 00108 /* 00109 * Returns the token parameter to use when fetching the next page. 00110 */ 00111 const string& next_page_token() const { return next_page_token_; } 00112 00113 /* 00114 * Sets the [scalar] request token identifying the next desired page. 00115 * 00116 * This is for service APIs that use scalar token values. 00117 * 00118 * @param[in] token Specifies the desired page. 00119 * @see Reset 00120 */ 00121 void set_next_page_token(int64 token) { 00122 if (token == 0) { 00123 set_next_page_token(""); 00124 } else { 00125 set_next_page_token(StrCat("", token)); 00126 } 00127 } 00128 00129 /* 00130 * Sets the [string] request token identifying the next desired page. 00131 * 00132 * This is for service APIs that use string token values. 00133 * 00134 * @param[in] token Specifies the desired page. 00135 * @see Reset 00136 */ 00137 void set_next_page_token(const StringPiece& token) { 00138 done_ = token.empty(); 00139 next_page_token_ = token.as_string(); 00140 } 00141 00142 private: 00143 HttpResponse http_response_; 00144 ClientServiceRequest* request_; 00145 string next_page_token_; 00146 00147 bool done_; 00148 00149 DISALLOW_COPY_AND_ASSIGN(BaseServiceRequestPager); 00150 }; 00151 00152 /* 00153 * A pager over referenced REST APIs having a standard paging interface. 00154 * @ingroup ClientServiceLayer 00155 * 00156 * This template relies on the existence of REQUEST.set_page_token and 00157 * RESPONSE.get_next_page_token methods to control the page iteration. 00158 * 00159 * This class does not own the request or data objects. See the 00160 * EncapsulatedServiceRequestPager as a variant that adds memory management. 00161 * 00162 * @tparam REQUEST must be a subclass of ClientServiceRequest 00163 * and have a set_page_token method. 00164 * @tparam DATA must be a subclass of SerializableJson and have a 00165 * get_next_page_token method. 00166 */ 00167 template<class REQUEST, class DATA> 00168 class ServiceRequestPager : public BaseServiceRequestPager { 00169 public: 00170 /* 00171 * Standard constructor. 00172 * 00173 * @param[in] request The prototype request used to fetch pages. 00174 * The caller retains ownershp. 00175 * @param[in] page_data_storage Holds the underlying response data returned 00176 * for the last requested page. The claeer retains ownership. 00177 */ 00178 ServiceRequestPager(REQUEST* request, DATA* page_data_storage) 00179 : BaseServiceRequestPager(request), page_data_storage_(page_data_storage) { 00180 } 00181 00182 /* 00183 * Standard destructor. 00184 */ 00185 virtual ~ServiceRequestPager() {} 00186 00187 /* 00188 * Returns the current page data. 00189 * 00190 * @return Ownership is retained by this instance as far at the caller is 00191 * concerned. 00192 */ 00193 DATA* data() { return page_data_storage_; } 00194 00195 /* 00196 * Returns the current page request. 00197 * 00198 * @return Ownership is retained by this instance as far at the caller is 00199 * concerned. 00200 */ 00201 REQUEST* request() { 00202 return static_cast<REQUEST*>(BaseServiceRequestPager::request()); 00203 } 00204 00205 /* 00206 * Fetches the next page, if any. 00207 * 00208 * To distinguish the difference between a failure and no more pages, 00209 * check the http_response()->http_status(). 00210 * 00211 * @return false on failure or when there are no more pages. 00212 */ 00213 virtual util::Status ExecuteNextPage() { 00214 // This method is called by the base class which guards with is_done 00215 // so we dont need to check here. But we'll do so anyway just to be 00216 // sure it didnt get here through some other route. 00217 if (is_done()) { 00218 return StatusOutOfRange("Finished Paging"); 00219 } 00220 00221 if (next_page_token().empty()) { 00222 request()->clear_page_token(); 00223 } else { 00224 request()->set_page_token(next_page_token()); 00225 } 00226 00227 util::Status status = 00228 request()->mutable_http_request()->PrepareToReuse(); 00229 if (!status.ok()) return status; 00230 00231 status = request()->ExecuteAndParseResponse(page_data_storage_); 00232 if (!status.ok()) return status; 00233 00234 set_next_page_token(page_data_storage_->get_next_page_token()); 00235 return status; 00236 } 00237 00238 private: 00239 DATA* page_data_storage_; 00240 00241 DISALLOW_COPY_AND_ASSIGN(ServiceRequestPager); 00242 }; 00243 00244 /* 00245 * A ServiceRequestPager that owns the request and data objects. 00246 * @ingroup ClientServiceLayer 00247 * 00248 * The request instance still needs to be injected since requests do not have 00249 * standard constructors. 00250 */ 00251 template<class REQUEST, class DATA> 00252 class EncapsulatedServiceRequestPager 00253 : public ServiceRequestPager<REQUEST, DATA> { 00254 public: 00255 /* 00256 * Standard constructor 00257 * 00258 * @param[in] request The request prototype used to ask for pages. 00259 */ 00260 explicit EncapsulatedServiceRequestPager(REQUEST* request) 00261 : ServiceRequestPager<REQUEST, DATA>(request, DATA::New()) { 00262 request_.reset(request); 00263 data_storage_.reset(ServiceRequestPager<REQUEST, DATA>::data()); 00264 } 00265 00266 /* 00267 * Standard destructor. 00268 */ 00269 virtual ~EncapsulatedServiceRequestPager() {} 00270 00271 private: 00272 scoped_ptr<REQUEST> request_; // access through base class 00273 scoped_ptr<DATA> data_storage_; // access through base class 00274 00275 DISALLOW_COPY_AND_ASSIGN(EncapsulatedServiceRequestPager); 00276 }; 00277 00278 } // namespace client 00279 00280 } // namespace googleapis 00281 #endif // APISERVING_CLIENTSCPP_SERVICE_SERVICE_REQUEST_PAGER_H_