OLD | NEW |
1 /* | 1 /* |
2 Copyright 2013 Google Inc | 2 Copyright 2013 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 |
(...skipping 24 matching lines...) Expand all Loading... |
35 | 35 |
36 namespace Google.Apis.Services | 36 namespace Google.Apis.Services |
37 { | 37 { |
38 /// <summary> | 38 /// <summary> |
39 /// A thread-safe base class for a client service which provides common mech
anism for all services, like· | 39 /// A thread-safe base class for a client service which provides common mech
anism for all services, like· |
40 /// serialization and GZip support. | 40 /// serialization and GZip support. |
41 /// This class adds a special <see cref="Google.Apis.Http.IHttpExecuteInterc
eptor"/> to the· | 41 /// This class adds a special <see cref="Google.Apis.Http.IHttpExecuteInterc
eptor"/> to the· |
42 /// <see cref="Google.Apis.Http.ConfigurableMessageHandler"/> execute interc
eptor list, which uses the given· | 42 /// <see cref="Google.Apis.Http.ConfigurableMessageHandler"/> execute interc
eptor list, which uses the given· |
43 /// Authenticator. It calls to its applying authentication method, and injec
ts the "Authorization" header in the· | 43 /// Authenticator. It calls to its applying authentication method, and injec
ts the "Authorization" header in the· |
44 /// request. | 44 /// request. |
45 /// If the given Authenticator implements <see cref="Google.Apis.Http.IUnsuc
cessfulReponseHandler"/>, this class | 45 /// If the given Authenticator implements <see cref="Google.Apis.Http.IHttpU
nsuccessfulResponseHandler"/>, this· |
46 /// adds the Authenticator to the <see cref="Google.Apis.Http.ConfigurableMe
ssageHandler"/>'s unsuccessful response | 46 /// class adds the Authenticator to the <see cref="Google.Apis.Http.Configur
ableMessageHandler"/>'s unsuccessful· |
47 /// handler list. | 47 /// response handler list. |
48 /// </summary> | 48 /// </summary> |
49 public abstract class BaseClientService : IClientService | 49 public abstract class BaseClientService : IClientService |
50 { | 50 { |
51 /// <summary> The class logger. </summary> | 51 /// <summary>The class logger.</summary> |
52 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy
pe<BaseClientService>(); | 52 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy
pe<BaseClientService>(); |
53 | 53 |
54 #region Initializer | 54 #region Initializer |
55 | 55 |
56 /// <summary>· | 56 /// <summary>An initializer class for the client service.</summary> |
57 /// Indicates if exponential back-off is used automatically on exception
in a service request and\or when 503· | |
58 /// response is returned form the server. | |
59 /// </summary> | |
60 [Flags] | |
61 public enum ExponentialBackOffPolicy | |
62 { | |
63 None = 0, | |
64 Exception = 1, | |
65 UnsuccessfulResponse503 = 2 | |
66 } | |
67 | |
68 /// <summary> An initializer class for the client service. </summary> | |
69 public class Initializer | 57 public class Initializer |
70 { | 58 { |
71 /// <summary> | 59 /// <summary> |
72 /// Gets or sets the factory for creating <see cref="System.Net.Http
.HttpClient"/> instance. If this· | 60 /// Gets or sets the factory for creating <see cref="System.Net.Http
.HttpClient"/> instance. If this· |
73 /// property is not set the service uses a new <see cref="Google.Api
s.Http.HttpClientFactory"/> instance. | 61 /// property is not set the service uses a new <see cref="Google.Api
s.Http.HttpClientFactory"/> instance. |
74 /// </summary> | 62 /// </summary> |
75 public IHttpClientFactory HttpClientFactory { get; set; } | 63 public IHttpClientFactory HttpClientFactory { get; set; } |
76 | 64 |
77 /// <summary> | 65 /// <summary> |
78 /// Gets or sets an Http client initializer which is able to customi
ze properties on· | 66 /// Gets or sets a HTTP client initializer which is able to customiz
e properties on· |
79 /// <see cref="Google.Apis.Http.ConfigurableHttpClient"/> and· | 67 /// <see cref="Google.Apis.Http.ConfigurableHttpClient"/> and· |
80 /// <see cref="Google.Apis.Http.ConfigurableMessageHandler"/>. | 68 /// <see cref="Google.Apis.Http.ConfigurableMessageHandler"/>. |
81 /// </summary> | 69 /// </summary> |
82 public IConfigurableHttpClientInitializer HttpClientInitializer { ge
t; set; } | 70 public IConfigurableHttpClientInitializer HttpClientInitializer { ge
t; set; } |
83 | 71 |
84 /// <summary> | 72 /// <summary> |
85 /// Get or sets the exponential back-off policy used by the service.
Default value is· | 73 /// Get or sets the exponential back-off policy used by the service.
Default value is· |
86 /// <c>UnsuccessfulResponse503</c>, which means that exponential bac
k-off is used on 503 abnormal HTTP | 74 /// <c>UnsuccessfulResponse503</c>, which means that exponential bac
k-off is used on 503 abnormal HTTP |
87 /// response. | 75 /// response. |
88 /// If the value is set to <c>None</c>, no exponential back-off poli
cy is used, and it's up to user to | 76 /// If the value is set to <c>None</c>, no exponential back-off poli
cy is used, and it's up to user to |
89 /// configure the <seealso cref="Google.Apis.Http.ConfigurableMessag
eHandler"/> in an | 77 /// configure the <seealso cref="Google.Apis.Http.ConfigurableMessag
eHandler"/> in an |
90 /// <seealso cref="Google.Apis.Http.IConfigurableHttpClientInitializ
er"/> to set a specific back-off | 78 /// <seealso cref="Google.Apis.Http.IConfigurableHttpClientInitializ
er"/> to set a specific back-off |
91 /// implementation (using <seealso cref="Google.Api.Http.BackOffHand
ler"/>). | 79 /// implementation (using <seealso cref="Google.Apis.Http.BackOffHan
dler"/>). |
92 /// </summary> | 80 /// </summary> |
93 public ExponentialBackOffPolicy DefaultExponentialBackOffPolicy { ge
t; set; } | 81 public ExponentialBackOffPolicy DefaultExponentialBackOffPolicy { ge
t; set; } |
94 | 82 |
95 /// <summary> Gets or sets whether this service supports GZip. Defau
lt value is <c>true</c>. </summary> | 83 /// <summary>Gets or sets whether this service supports GZip. Defaul
t value is <c>true</c>.</summary> |
96 public bool GZipEnabled { get; set; } | 84 public bool GZipEnabled { get; set; } |
97 | 85 |
98 /// <summary> | 86 /// <summary> |
99 /// Gets and Sets the Serializer. Default value is <see cref="Google
.Apis.Json.NewtonsoftJsonSerializer"/>. | 87 /// Gets and Sets the serializer. Default value is <see cref="Google
.Apis.Json.NewtonsoftJsonSerializer"/>. |
100 /// </summary> | 88 /// </summary> |
101 public ISerializer Serializer { get; set; } | 89 public ISerializer Serializer { get; set; } |
102 | 90 |
103 /// <summary> Gets or sets the API Key. Default value is <c>null</c>
. </summary> | 91 /// <summary>Gets or sets the API Key. Default value is <c>null</c>.
</summary> |
104 public string ApiKey { get; set; } | 92 public string ApiKey { get; set; } |
105 | 93 |
106 /// <summary> | 94 /// <summary> |
107 /// Gets or sets the Authenticator. Default value is· | 95 /// Gets or sets the Authenticator. Default value is· |
108 /// <see cref="Google.Apis.Authentication.NullAuthenticator.Instance
"/>. | 96 /// <see cref="Google.Apis.Authentication.NullAuthenticator.Instance
"/>. |
109 /// </summary> | 97 /// </summary> |
110 public IAuthenticator Authenticator { get; set; } | 98 public IAuthenticator Authenticator { get; set; } |
111 | 99 |
112 /// <summary> | 100 /// <summary> |
113 /// Gets or sets Application name to be used in the User-Agent heade
r. Default value is <c>null</c>.· | 101 /// Gets or sets Application name to be used in the User-Agent heade
r. Default value is <c>null</c>.· |
114 /// </summary> | 102 /// </summary> |
115 public string ApplicationName { get; set; } | 103 public string ApplicationName { get; set; } |
116 | 104 |
117 /// <summary> Constructs a new initializer with default values. </su
mmary> | 105 /// <summary>Constructs a new initializer with default values.</summ
ary> |
118 public Initializer() | 106 public Initializer() |
119 { | 107 { |
120 GZipEnabled = true; | 108 GZipEnabled = true; |
121 Serializer = new NewtonsoftJsonSerializer(); | 109 Serializer = new NewtonsoftJsonSerializer(); |
122 Authenticator = NullAuthenticator.Instance; | 110 Authenticator = NullAuthenticator.Instance; |
123 DefaultExponentialBackOffPolicy = ExponentialBackOffPolicy.Unsuc
cessfulResponse503; | 111 DefaultExponentialBackOffPolicy = ExponentialBackOffPolicy.Unsuc
cessfulResponse503; |
124 } | 112 } |
125 } | 113 } |
126 | 114 |
127 /// <summary> | |
128 /// An initializer which adds exponential back-off as exception handler
and\or unsuccessful response handler by | |
129 /// the given <seealso cref="BaseClientService.ExponentialBackOffPolicy"
/>. | |
130 /// </summary> | |
131 private class ExponentialBackOffInitializer : IConfigurableHttpClientIni
tializer | |
132 { | |
133 private ExponentialBackOffPolicy Policy { get; set; } | |
134 private Func<BackOffHandler> CreateBackOff { get; set; } | |
135 | |
136 /// <summary> | |
137 /// Constructs a new back-off initializer with the given policy and
back-off handler create function. | |
138 /// </summary> | |
139 public ExponentialBackOffInitializer(ExponentialBackOffPolicy policy
, Func<BackOffHandler> createBackOff) | |
140 { | |
141 Policy = policy; | |
142 CreateBackOff = createBackOff; | |
143 } | |
144 | |
145 public void Initialize(ConfigurableHttpClient httpClient) | |
146 { | |
147 var backOff = CreateBackOff(); | |
148 | |
149 // add exception handler and\or unsuccessful response handler | |
150 if ((Policy & ExponentialBackOffPolicy.Exception) == Exponential
BackOffPolicy.Exception) | |
151 { | |
152 httpClient.MessageHandler.ExceptionHandlers.Add(backOff); | |
153 } | |
154 | |
155 if ((Policy & ExponentialBackOffPolicy.UnsuccessfulResponse503)
== | |
156 ExponentialBackOffPolicy.UnsuccessfulResponse503) | |
157 { | |
158 httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(b
ackOff); | |
159 } | |
160 } | |
161 } | |
162 | |
163 #endregion | 115 #endregion |
164 | 116 |
165 /// <summary> Constructs a new base client with the specified initialize
r. </summary> | 117 /// <summary>Constructs a new base client with the specified initializer
.</summary> |
166 protected BaseClientService(Initializer initializer) | 118 protected BaseClientService(Initializer initializer) |
167 { | 119 { |
168 // sets the right properties by the initializer's properties | 120 // Set the right properties by the initializer's properties. |
169 GZipEnabled = initializer.GZipEnabled; | 121 GZipEnabled = initializer.GZipEnabled; |
170 Serializer = initializer.Serializer; | 122 Serializer = initializer.Serializer; |
171 ApiKey = initializer.ApiKey; | 123 ApiKey = initializer.ApiKey; |
172 Authenticator = initializer.Authenticator; | 124 Authenticator = initializer.Authenticator; |
173 ApplicationName = initializer.ApplicationName; | 125 ApplicationName = initializer.ApplicationName; |
174 if (ApplicationName == null) | 126 if (ApplicationName == null) |
175 { | 127 { |
176 Logger.Warning("Application name is not set. Please set Initiali
zer.ApplicationName property"); | 128 Logger.Warning("Application name is not set. Please set Initiali
zer.ApplicationName property"); |
177 } | 129 } |
178 HttpClientInitializer = initializer.HttpClientInitializer; | 130 HttpClientInitializer = initializer.HttpClientInitializer; |
179 | 131 |
180 // create an Http client for this service | 132 // Create a HTTP client for this service. |
181 HttpClient = CreateHttpClient(initializer); | 133 HttpClient = CreateHttpClient(initializer); |
182 } | 134 } |
183 | 135 |
184 /// <summary> Return <c>true</c> if this service contains the specified
feature. </summary> | 136 /// <summary>Returns <c>true</c> if this service contains the specified
feature.</summary> |
185 private bool HasFeature(Features feature) | 137 private bool HasFeature(Features feature) |
186 { | 138 { |
187 return Features.Contains(feature.GetStringValue()); | 139 return Features.Contains(feature.GetStringValue()); |
188 } | 140 } |
189 | 141 |
190 private ConfigurableHttpClient CreateHttpClient(Initializer initializer) | 142 private ConfigurableHttpClient CreateHttpClient(Initializer initializer) |
191 { | 143 { |
192 // if factory wasn't set use the default Http client factory | 144 // If factory wasn't set use the default HTTP client factory. |
193 var factory = initializer.HttpClientFactory ?? new HttpClientFactory
(); | 145 var factory = initializer.HttpClientFactory ?? new HttpClientFactory
(); |
194 var args = new CreateHttpClientArgs | 146 var args = new CreateHttpClientArgs |
195 { | 147 { |
196 GZipEnabled = GZipEnabled, | 148 GZipEnabled = GZipEnabled, |
197 ApplicationName = ApplicationName, | 149 ApplicationName = ApplicationName, |
198 }; | 150 }; |
199 | 151 |
200 // add the user's input initializer | 152 // Add the user's input initializer. |
201 if (HttpClientInitializer != null) | 153 if (HttpClientInitializer != null) |
202 { | 154 { |
203 args.Initializers.Add(HttpClientInitializer); | 155 args.Initializers.Add(HttpClientInitializer); |
204 } | 156 } |
205 | 157 |
206 // add exponential back-off initializer if necessary | 158 // Add exponential back-off initializer if necessary. |
207 if (initializer.DefaultExponentialBackOffPolicy != ExponentialBackOf
fPolicy.None) | 159 if (initializer.DefaultExponentialBackOffPolicy != ExponentialBackOf
fPolicy.None) |
208 { | 160 { |
209 args.Initializers.Add(new ExponentialBackOffInitializer(initiali
zer.DefaultExponentialBackOffPolicy, | 161 args.Initializers.Add(new ExponentialBackOffInitializer(initiali
zer.DefaultExponentialBackOffPolicy, |
210 CreateBackOffHandler)); | 162 CreateBackOffHandler)); |
211 } | 163 } |
212 | 164 |
213 // add authenticator initializer to intercept a request and add the
"Authorization" header and also handle | 165 // Add authenticator initializer to intercept a request and add the
"Authorization" header and also handle |
214 // abnormal 401 responses in case the authenticator is an instance o
f unsuccessful response handler. | 166 // abnormal 401 responses in case the authenticator is an instance o
f unsuccessful response handler. |
215 args.Initializers.Add(new AuthenticatorMessageHandlerInitializer(Aut
henticator)); | 167 args.Initializers.Add(new AuthenticatorMessageHandlerInitializer(Aut
henticator)); |
216 | 168 |
217 return factory.CreateHttpClient(args); | 169 return factory.CreateHttpClient(args); |
218 } | 170 } |
219 | 171 |
220 /// <summary> | 172 /// <summary> |
221 /// Creates the back-off handler with <seealso cref="Google.Apis.Util.Ex
ponentialBackOff"/>.· | 173 /// Creates the back-off handler with <seealso cref="Google.Apis.Util.Ex
ponentialBackOff"/>.· |
222 /// Overrides this method to change the default behavior of back-off han
dler (e.g. you can change the maximum | 174 /// Overrides this method to change the default behavior of back-off han
dler (e.g. you can change the maximum |
223 /// waited request's time span, or create a back-off handler with you ow
n implementation of· | 175 /// waited request's time span, or create a back-off handler with you ow
n implementation of· |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 public ISerializer Serializer { get; private set; } | 229 public ISerializer Serializer { get; private set; } |
278 | 230 |
279 public virtual string SerializeObject(object obj) | 231 public virtual string SerializeObject(object obj) |
280 { | 232 { |
281 if (HasFeature(Discovery.Features.LegacyDataResponse)) | 233 if (HasFeature(Discovery.Features.LegacyDataResponse)) |
282 { | 234 { |
283 // Legacy path | 235 // Legacy path |
284 var request = new StandardResponse<object> { Data = obj }; | 236 var request = new StandardResponse<object> { Data = obj }; |
285 return Serializer.Serialize(request); | 237 return Serializer.Serialize(request); |
286 } | 238 } |
287 | |
288 // New v1.0 path | |
289 return Serializer.Serialize(obj); | 239 return Serializer.Serialize(obj); |
290 } | 240 } |
291 | 241 |
292 public virtual async Task<T> DeserializeResponse<T>(HttpResponseMessage
response) | 242 public virtual async Task<T> DeserializeResponse<T>(HttpResponseMessage
response) |
293 { | 243 { |
294 var text = await response.Content.ReadAsStringAsync().ConfigureAwait
(false); | 244 var text = await response.Content.ReadAsStringAsync().ConfigureAwait
(false); |
295 | 245 |
296 // If a string is request, don't parse the response. | 246 // If a string is request, don't parse the response. |
297 if (typeof(T).Equals(typeof(string))) | 247 if (typeof(T).Equals(typeof(string))) |
298 { | 248 { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 // Standard response (which contains data and error properties) | 317 // Standard response (which contains data and error properties) |
368 throw new GoogleApiException(Name, | 318 throw new GoogleApiException(Name, |
369 "An Error occurred, but the error response could not be dese
rialized", ex); | 319 "An Error occurred, but the error response could not be dese
rialized", ex); |
370 } | 320 } |
371 | 321 |
372 return errorResponse.Error; | 322 return errorResponse.Error; |
373 } | 323 } |
374 | 324 |
375 #endregion | 325 #endregion |
376 | 326 |
377 #region Abstract Memebrs | 327 #region Abstract Members |
378 | 328 |
379 public abstract string Name { get; } | 329 public abstract string Name { get; } |
380 public abstract string BaseUri { get; } | 330 public abstract string BaseUri { get; } |
381 public abstract string BasePath { get; } | 331 public abstract string BasePath { get; } |
382 | 332 |
383 public abstract IList<string> Features { get; } | 333 public abstract IList<string> Features { get; } |
384 | 334 |
385 #endregion | 335 #endregion |
386 | 336 |
387 #endregion | 337 #endregion |
388 | 338 |
389 /// <summary> Creates a GZip stream by the given serialized object. </su
mmary> | 339 /// <summary>Creates a GZip stream by the given serialized object.</summ
ary> |
390 private static Stream CreateGZipStream(string serializedObject) | 340 private static Stream CreateGZipStream(string serializedObject) |
391 { | 341 { |
392 byte[] bytes = System.Text.Encoding.UTF8.GetBytes(serializedObject); | 342 byte[] bytes = System.Text.Encoding.UTF8.GetBytes(serializedObject); |
393 using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) | 343 using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) |
394 { | 344 { |
395 using (GZipStream gzip = new GZipStream(ms, CompressionMode.Comp
ress, true)) | 345 using (GZipStream gzip = new GZipStream(ms, CompressionMode.Comp
ress, true)) |
396 { | 346 { |
397 gzip.Write(bytes, 0, bytes.Length); | 347 gzip.Write(bytes, 0, bytes.Length); |
398 } | 348 } |
399 | 349 |
400 // reset the stream to the beginning. It doesn't work otherwise! | 350 // reset the stream to the beginning. It doesn't work otherwise! |
401 ms.Position = 0; | 351 ms.Position = 0; |
402 byte[] compressed = new byte[ms.Length]; | 352 byte[] compressed = new byte[ms.Length]; |
403 ms.Read(compressed, 0, compressed.Length); | 353 ms.Read(compressed, 0, compressed.Length); |
404 return new MemoryStream(compressed); | 354 return new MemoryStream(compressed); |
405 } | 355 } |
406 } | 356 } |
407 | 357 |
408 public virtual void Dispose() | 358 public virtual void Dispose() |
409 { | 359 { |
410 if (HttpClient != null) | 360 if (HttpClient != null) |
411 { | 361 { |
412 HttpClient.Dispose(); | 362 HttpClient.Dispose(); |
413 } | 363 } |
414 } | 364 } |
415 } | 365 } |
416 } | 366 } |
OLD | NEW |