Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(755)

Delta Between Two Patch Sets: Src/GoogleApis/Apis/Requests/ClientServiceRequest.cs

Issue 13412046: Reimplement OAuth2 library - Step 1 (Closed) Base URL: https://google-api-dotnet-client.googlecode.com/hg/
Left Patch Set: all tests are running Created 10 years, 10 months ago
Right Patch Set: minor Created 10 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 /* 1 /*
2 Copyright 2011 Google Inc 2 Copyright 2011 Google Inc
3 3
4 Licensed under the Apache License, Version 2.0 (the "License"); 4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License. 5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at 6 You may obtain a copy of the License at
7 7
8 http://www.apache.org/licenses/LICENSE-2.0 8 http://www.apache.org/licenses/LICENSE-2.0
9 9
10 Unless required by applicable law or agreed to in writing, software 10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS, 11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and 13 See the License for the specific language governing permissions and
14 limitations under the License. 14 limitations under the License.
15 */ 15 */
16 16
17 using System; 17 using System;
18 using System.Collections.Generic; 18 using System.Collections.Generic;
19 using System.IO; 19 using System.IO;
20 using System.Linq;
21 using System.Net.Http; 20 using System.Net.Http;
22 using System.Net.Http.Headers; 21 using System.Net.Http.Headers;
23 using System.Reflection;
24 using System.Threading; 22 using System.Threading;
25 using System.Threading.Tasks; 23 using System.Threading.Tasks;
26 24
27 using Google.Apis.Discovery; 25 using Google.Apis.Discovery;
28 using Google.Apis.Http; 26 using Google.Apis.Http;
29 using Google.Apis.Logging; 27 using Google.Apis.Logging;
30 using Google.Apis.Services; 28 using Google.Apis.Services;
31 using Google.Apis.Testing; 29 using Google.Apis.Testing;
32 using Google.Apis.Util; 30 using Google.Apis.Util;
33 using Google.Apis.Requests.Parameters; 31 using Google.Apis.Requests.Parameters;
34 32
35 namespace Google.Apis.Requests 33 namespace Google.Apis.Requests
36 { 34 {
37 /// <summary> 35 /// <summary>
38 /// Represents an abstract, strongly typed request base class to make reques ts to a service. 36 /// Represents an abstract, strongly typed request base class to make reques ts to a service.
39 /// Supports a strongly typed response. 37 /// Supports a strongly typed response.
40 /// </summary> 38 /// </summary>
41 /// <typeparam name="TResponse">The type of the response object</typeparam> 39 /// <typeparam name="TResponse">The type of the response object</typeparam>
42 public abstract class ClientServiceRequest<TResponse> : IClientServiceReques t<TResponse> 40 public abstract class ClientServiceRequest<TResponse> : IClientServiceReques t<TResponse>
43 { 41 {
44 /// <summary> The class logger </summary> 42 /// <summary>The class logger.</summary>
45 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy pe<ClientServiceRequest<TResponse>>(); 43 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy pe<ClientServiceRequest<TResponse>>();
46 44
47 /// <summary> The service on which this request will be executed. </summ ary> 45 /// <summary>The service on which this request will be executed.</summar y>
48 private readonly IClientService service; 46 private readonly IClientService service;
49 47
50 /// <summary> Defines whether the E-Tag will be used in a specified way or be ignored. </summary> 48 /// <summary>Defines whether the E-Tag will be used in a specified way o r be ignored.</summary>
51 public ETagAction ETagAction { get; set; } 49 public ETagAction ETagAction { get; set; }
52 50
53 #region IClientServiceRequest Properties 51 #region IClientServiceRequest Properties
54 52
55 public abstract string MethodName { get; } 53 public abstract string MethodName { get; }
56 public abstract string RestPath { get; } 54 public abstract string RestPath { get; }
57 public abstract string HttpMethod { get; } 55 public abstract string HttpMethod { get; }
58 56
59 public IDictionary<string, IParameter> RequestParameters { get; private set; } 57 public IDictionary<string, IParameter> RequestParameters { get; private set; }
60 58
61 public IClientService Service 59 public IClientService Service
62 { 60 {
63 get { return service; } 61 get { return service; }
64 } 62 }
65 63
66 #endregion 64 #endregion
67 65
68 /// <summary> Creates a new service request. </summary> 66 /// <summary>Creates a new service request.</summary>
69 protected ClientServiceRequest(IClientService service) 67 protected ClientServiceRequest(IClientService service)
70 { 68 {
71 this.service = service; 69 this.service = service;
72 } 70 }
73 71
74 /// <summary> 72 /// <summary>
75 /// Initializes request's parameters. Inherited classes MUST override th is method to add parameters to the 73 /// Initializes request's parameters. Inherited classes MUST override th is method to add parameters to the
76 /// <see cref="RequestParameters"/> dictionary. 74 /// <see cref="RequestParameters"/> dictionary.
77 /// </summary> 75 /// </summary>
78 protected virtual void InitParameters() 76 protected virtual void InitParameters()
79 { 77 {
80 RequestParameters = new Dictionary<string, IParameter>(); 78 RequestParameters = new Dictionary<string, IParameter>();
81 } 79 }
82 80
83 #region Execution 81 #region Execution
84 82
85 public TResponse Execute() 83 public TResponse Execute()
86 { 84 {
87 try 85 try
88 { 86 {
89 using (var response = ExecuteUnparsed(CancellationToken.None).Re sult) 87 using (var response = ExecuteUnparsed(CancellationToken.None).Re sult)
90 { 88 {
91 return ParseResponse(response).Result; 89 return ParseResponse(response).Result;
92 } 90 }
93 } 91 }
94 catch (AggregateException aex) 92 catch (AggregateException aex)
95 { 93 {
96 // if an exception was thrown during the tasks, unwrap and throw it 94 // If an exception was thrown during the tasks, unwrap and throw it.
97 throw aex.InnerException; 95 throw aex.InnerException;
98 } 96 }
99 catch (Exception ex) 97 catch (Exception ex)
100 { 98 {
101 throw ex; 99 throw ex;
102 } 100 }
103 } 101 }
104 102
105 public Stream ExecuteAsStream() 103 public Stream ExecuteAsStream()
106 { 104 {
107 // TODO(peleyal): should we copy the stream, and dispose the respons e? 105 // TODO(peleyal): should we copy the stream, and dispose the respons e?
108 try 106 try
109 { 107 {
110 // sync call 108 // Sync call.
111 var response = ExecuteUnparsed(CancellationToken.None).Result; 109 var response = ExecuteUnparsed(CancellationToken.None).Result;
112 return response.Content.ReadAsStreamAsync().Result; 110 return response.Content.ReadAsStreamAsync().Result;
113 } 111 }
114 catch (AggregateException aex) 112 catch (AggregateException aex)
115 { 113 {
116 // if an exception was thrown during the tasks, unwrap and throw it 114 // If an exception was thrown during the tasks, unwrap and throw it.
117 throw aex.InnerException; 115 throw aex.InnerException;
118 } 116 }
119 catch (Exception ex) 117 catch (Exception ex)
120 { 118 {
121 throw ex; 119 throw ex;
122 } 120 }
123 } 121 }
124 122
125 public async Task<TResponse> ExecuteAsync() 123 public async Task<TResponse> ExecuteAsync()
126 { 124 {
(...skipping 18 matching lines...) Expand all
145 { 143 {
146 // TODO(peleyal): should we copy the stream, and dispose the respons e? 144 // TODO(peleyal): should we copy the stream, and dispose the respons e?
147 var response = await ExecuteAsyncUnparsed(cancellationToken).Configu reAwait(false); 145 var response = await ExecuteAsyncUnparsed(cancellationToken).Configu reAwait(false);
148 146
149 cancellationToken.ThrowIfCancellationRequested(); 147 cancellationToken.ThrowIfCancellationRequested();
150 return await response.Content.ReadAsStreamAsync().ConfigureAwait(fal se); 148 return await response.Content.ReadAsStreamAsync().ConfigureAwait(fal se);
151 } 149 }
152 150
153 #region Helpers 151 #region Helpers
154 152
155 /// <summary> Sync executes the request without parsing the result. </su mmary> 153 /// <summary>Sync executes the request without parsing the result. </sum mary>
156 private async Task<HttpResponseMessage> ExecuteUnparsed(CancellationToke n cancellationToken) 154 private async Task<HttpResponseMessage> ExecuteUnparsed(CancellationToke n cancellationToken)
157 { 155 {
158 using (var request = CreateRequest()) 156 using (var request = CreateRequest())
159 { 157 {
160 return await service.HttpClient.SendAsync(request, cancellationT oken).ConfigureAwait(false); 158 return await service.HttpClient.SendAsync(request, cancellationT oken).ConfigureAwait(false);
161 } 159 }
162 } 160 }
163 161
164 /// <summary> Async executes the request without parsing the result. </s ummary> 162 /// <summary>Async executes the request without parsing the result. </su mmary>
165 private Task<HttpResponseMessage> ExecuteAsyncUnparsed(CancellationToken cancellationToken) 163 private Task<HttpResponseMessage> ExecuteAsyncUnparsed(CancellationToken cancellationToken)
166 { 164 {
167 // TODO(peleyal): remove the creation of a new Task (it's not necess ary). 165 // TODO(peleyal): remove the creation of a new Task (it's not necess ary).
168 // It should also be removed from ResumableMediaUpload and MediaDown loader! 166 // It should also be removed from ResumableMediaUpload and MediaDown loader!
169
170 // create a new task completion source and return its task. In addit ional task we actually send the request 167 // create a new task completion source and return its task. In addit ional task we actually send the request
171 // using ExecuteUnparsed and setting the result or the exception on the completion source 168 // using ExecuteUnparsed and setting the result or the exception on the completion source
172 TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSo urce<HttpResponseMessage>(); 169 TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSo urce<HttpResponseMessage>();
173 Task.Factory.StartNew(async () => 170 Task.Factory.StartNew(async () =>
174 { 171 {
175 try 172 try
176 { 173 {
177 var response = await ExecuteUnparsed(cancellationToken). ConfigureAwait(false); 174 var response = await ExecuteUnparsed(cancellationToken). ConfigureAwait(false);
178 tcs.SetResult(response); 175 tcs.SetResult(response);
179 } 176 }
180 catch (Exception ex) 177 catch (Exception ex)
181 { 178 {
182 // exception was thrown - it must be set on the task com pletion source 179 // Exception was thrown - it must be set on the task com pletion source.
183 tcs.SetException(ex); 180 tcs.SetException(ex);
184 } 181 }
185 }).ConfigureAwait(false); 182 }).ConfigureAwait(false);
186 return tcs.Task; 183 return tcs.Task;
187 } 184 }
188 185
189 /// <summary> Parses the response and deserialize the content into the r equested response object. </summary> 186 /// <summary>Parses the response and deserialize the content into the re quested response object. </summary>
190 private async Task<TResponse> ParseResponse(HttpResponseMessage response ) 187 private async Task<TResponse> ParseResponse(HttpResponseMessage response )
191 { 188 {
192 if (response.IsSuccessStatusCode) 189 if (response.IsSuccessStatusCode)
193 { 190 {
194 return await service.DeserializeResponse<TResponse>(response).Co nfigureAwait(false); 191 return await service.DeserializeResponse<TResponse>(response).Co nfigureAwait(false);
195 } 192 }
196 var error = await service.DeserializeError(response).ConfigureAwait( false); 193 var error = await service.DeserializeError(response).ConfigureAwait( false);
197 throw new GoogleApiException(service.Name, error.ToString()); 194 throw new GoogleApiException(service.Name, error.ToString());
198 } 195 }
199 196
200 #endregion 197 #endregion
201 198
202 #endregion 199 #endregion
203 200
204 /// <summary> 201 /// <summary>
205 /// Creates the <seealso cref="Google.Apis.Requests.RequestBuilder"/> wh ich is used to generate a request. 202 /// Creates the <seealso cref="Google.Apis.Requests.RequestBuilder"/> wh ich is used to generate a request.
206 /// </summary> 203 /// </summary>
207 /// <returns> 204 /// <returns>
208 /// A new builder instance which contains the HTTP method and the right Uri with its path and query parameters. 205 /// A new builder instance which contains the HTTP method and the right Uri with its path and query parameters.
209 /// </returns> 206 /// </returns>
210 private RequestBuilder CreateBuilder() 207 private RequestBuilder CreateBuilder()
211 { 208 {
212 var builder = new RequestBuilder() 209 var builder = new RequestBuilder()
213 { 210 {
214 BaseUri = new Uri(Service.BaseUri), 211 BaseUri = new Uri(Service.BaseUri),
215 Path = RestPath, 212 Path = RestPath,
216 Method = HttpMethod, 213 Method = HttpMethod,
217 }; 214 };
218 215
219 // init parameters 216 // Init parameters.
220 builder.AddParameter(RequestParameterType.Query, "key", service.ApiK ey); 217 builder.AddParameter(RequestParameterType.Query, "key", service.ApiK ey);
221 var parameters = ParameterUtils.CreateParameterDictionary(this); 218 var parameters = ParameterUtils.CreateParameterDictionary(this);
222 AddParameters(builder, ParameterCollection.FromDictionary(parameters )); 219 AddParameters(builder, ParameterCollection.FromDictionary(parameters ));
223 return builder; 220 return builder;
224 } 221 }
225 222
226 /// <summary>Generates the right Url for this request.</summary> 223 /// <summary>Generates the right URL for this request.</summary>
227 protected string GenerateRequestUri() 224 protected string GenerateRequestUri()
228 { 225 {
229 return CreateBuilder().BuildUri().ToString(); 226 return CreateBuilder().BuildUri().ToString();
230 } 227 }
231 228
232 /// <summary>Creates a HTTP request message with all class parameters, d eveloper-key, ETag, etc.</summary> 229 /// <summary>Creates a HTTP request message with all class parameters, d eveloper-key, ETag, etc.</summary>
233 [VisibleForTestOnly] 230 [VisibleForTestOnly]
234 internal HttpRequestMessage CreateRequest() 231 internal HttpRequestMessage CreateRequest()
235 { 232 {
236 var builder = CreateBuilder(); 233 var builder = CreateBuilder();
237 var request = builder.CreateRequest(); 234 var request = builder.CreateRequest();
238 object body = GetBody(); 235 object body = GetBody();
239 if (body != null) 236 if (body != null)
240 { 237 {
241 service.SetRequestSerailizedContent(request, body); 238 service.SetRequestSerailizedContent(request, body);
242 } 239 }
243 240
244 AddETag(request); 241 AddETag(request);
245 return request; 242 return request;
246 } 243 }
247 244
248 protected virtual object GetBody() 245 protected virtual object GetBody()
249 { 246 {
250 return null; 247 return null;
251 } 248 }
252 249
253 #region ETag 250 #region ETag
254 251
255 /// <summary> 252 /// <summary>
256 /// Adds the right ETag action (e.g. If-Match) header to the given HTTP request if the body contains ETag. 253 /// Adds the right ETag action (e.g. If-Match) header to the given HTTP request if the body contains ETag.
257 /// </summary> 254 /// </summary>
258 private void AddETag(HttpRequestMessage request) 255 private void AddETag(HttpRequestMessage request)
259 { 256 {
260 IDirectResponseSchema body = GetBody() as IDirectResponseSchema; 257 IDirectResponseSchema body = GetBody() as IDirectResponseSchema;
261 if (body != null && !string.IsNullOrEmpty(body.ETag)) 258 if (body != null && !string.IsNullOrEmpty(body.ETag))
262 { 259 {
263 ETagAction action = ETagAction == ETagAction.Default ? GetDefaul tETagAction(HttpMethod) : ETagAction; 260 ETagAction action = ETagAction == ETagAction.Default ? GetDefaul tETagAction(HttpMethod) : ETagAction;
264 switch (action) 261 switch (action)
265 { 262 {
266 case ETagAction.IfMatch: 263 case ETagAction.IfMatch:
267 request.Headers.IfMatch.Add(new EntityTagHeaderValue(bod y.ETag)); 264 request.Headers.IfMatch.Add(new EntityTagHeaderValue(bod y.ETag));
268 break; 265 break;
269 case ETagAction.IfNoneMatch: 266 case ETagAction.IfNoneMatch:
270 request.Headers.IfNoneMatch.Add(new EntityTagHeaderValue (body.ETag)); 267 request.Headers.IfNoneMatch.Add(new EntityTagHeaderValue (body.ETag));
271 break; 268 break;
272 } 269 }
273 } 270 }
274 } 271 }
275 272
276 /// <summary> 273 /// <summary>Returns the default ETagAction for a specific HTTP verb.</s ummary>
277 /// Returns the default ETagAction for a specific HTTP verb.
278 /// </summary>
279 [VisibleForTestOnly] 274 [VisibleForTestOnly]
280 internal static ETagAction GetDefaultETagAction(string httpMethod) 275 internal static ETagAction GetDefaultETagAction(string httpMethod)
281 { 276 {
282 switch (httpMethod) 277 switch (httpMethod)
283 { 278 {
284 // Incoming data should only be updated if it has been changed o n the server. 279 // Incoming data should only be updated if it has been changed o n the server.
285 case HttpConsts.Get: 280 case HttpConsts.Get:
286 return ETagAction.IfNoneMatch; 281 return ETagAction.IfNoneMatch;
287 282
288 // Outgoing data should only be committed if it hasn't been chan ged on the server. 283 // Outgoing data should only be committed if it hasn't been chan ged on the server.
289 case HttpConsts.Put: 284 case HttpConsts.Put:
290 case HttpConsts.Post: 285 case HttpConsts.Post:
291 case HttpConsts.Patch: 286 case HttpConsts.Patch:
292 case HttpConsts.Delete: 287 case HttpConsts.Delete:
293 return ETagAction.IfMatch; 288 return ETagAction.IfMatch;
294 289
295 default: 290 default:
296 return ETagAction.Ignore; 291 return ETagAction.Ignore;
297 } 292 }
298 } 293 }
299 294
300 #endregion 295 #endregion
301 296
302 #region Parameters 297 #region Parameters
303 298
304 /// <summary> Adds path and query parameters to the given <c>requestBuil der</c>. </summary> 299 /// <summary>Adds path and query parameters to the given <c>requestBuild er</c>.</summary>
305 private void AddParameters(RequestBuilder requestBuilder, ParameterColle ction inputParameters) 300 private void AddParameters(RequestBuilder requestBuilder, ParameterColle ction inputParameters)
306 { 301 {
307 foreach (var parameter in inputParameters) 302 foreach (var parameter in inputParameters)
308 { 303 {
309 IParameter parameterDefinition; 304 IParameter parameterDefinition;
310 305
311 if (!RequestParameters.TryGetValue(parameter.Key, out parameterD efinition)) 306 if (!RequestParameters.TryGetValue(parameter.Key, out parameterD efinition))
312 { 307 {
313 throw new GoogleApiException(Service.Name, 308 throw new GoogleApiException(Service.Name,
314 String.Format("Invalid parameter \"{0}\" was specified", parameter.Key)); 309 String.Format("Invalid parameter \"{0}\" was specified", parameter.Key));
(...skipping 23 matching lines...) Expand all
338 requestBuilder.AddParameter(RequestParameterType.Que ry, parameter.Key, value); 333 requestBuilder.AddParameter(RequestParameterType.Que ry, parameter.Key, value);
339 } 334 }
340 break; 335 break;
341 default: 336 default:
342 throw new GoogleApiException(service.Name, 337 throw new GoogleApiException(service.Name,
343 string.Format("Unsupported parameter type \"{0}\" fo r \"{1}\"", 338 string.Format("Unsupported parameter type \"{0}\" fo r \"{1}\"",
344 parameterDefinition.ParameterType, parameterDefiniti on.Name)); 339 parameterDefinition.ParameterType, parameterDefiniti on.Name));
345 } 340 }
346 } 341 }
347 342
348 // check if there is a required parameter which wasn't set 343 // Check if there is a required parameter which wasn't set.
349 foreach (var parameter in RequestParameters.Values) 344 foreach (var parameter in RequestParameters.Values)
350 { 345 {
351 if (parameter.IsRequired && !inputParameters.ContainsKey(paramet er.Name)) 346 if (parameter.IsRequired && !inputParameters.ContainsKey(paramet er.Name))
352 { 347 {
353 throw new GoogleApiException(service.Name, 348 throw new GoogleApiException(service.Name,
354 string.Format("Parameter \"{0}\" is missing", parameter. Name)); 349 string.Format("Parameter \"{0}\" is missing", parameter. Name));
355 } 350 }
356 } 351 }
357 } 352 }
358 353
359 #endregion 354 #endregion
360 } 355 }
361 } 356 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b