21
21
import java .util .Map ;
22
22
23
23
import javax .ws .rs .core .MediaType ;
24
+ import javax .xml .parsers .DocumentBuilder ;
25
+ import javax .xml .parsers .DocumentBuilderFactory ;
24
26
import javax .xml .parsers .ParserConfigurationException ;
25
27
import javax .xml .transform .OutputKeys ;
26
28
import javax .xml .transform .Transformer ;
@@ -62,6 +64,9 @@ public class ZencoderClient implements IZencoderClient {
62
64
private final String zencoderAPIKey ;
63
65
private final ZencoderAPIVersion zencoderAPIVersion ;
64
66
private XPath xPath ;
67
+
68
+ private final int MAX_CONNECTION_ATTEMPTS = 5 ;
69
+ private int currentConnectionAttempt = 0 ;
65
70
66
71
public ZencoderClient (String zencoderApiKey ) {
67
72
this (zencoderApiKey , ZencoderAPIVersion .API_V1 );
@@ -77,6 +82,11 @@ public ZencoderClient(String zencoderApiKey, ZencoderAPIVersion apiVersion) {
77
82
78
83
httpClient = ApacheHttpClient .create ();
79
84
httpClient .setFollowRedirects (true );
85
+
86
+ // set a 20 second timeout on the client
87
+ httpClient .setConnectTimeout (20000 );
88
+ httpClient .setReadTimeout (20000 );
89
+
80
90
xPath = XPathFactory .newInstance ().newXPath ();
81
91
zencoderAPIBaseUrl = zencoderAPIVersion .getBaseUrl ();
82
92
}
@@ -138,35 +148,77 @@ private void completeJobInfo(ZencoderJob job, Document response) {
138
148
LOGGER .error ("XPath threw Exception" , e );
139
149
}
140
150
}
151
+
152
+ private void resetConnectionCount () {
153
+ // reset to 0 for use in tracking connections next time
154
+ currentConnectionAttempt = 0 ;
155
+ }
156
+
157
+ private Document createDocumentForException (String message ) {
158
+ try {
159
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory .newInstance ();
160
+ DocumentBuilder documentBuilder = documentBuilderFactory .newDocumentBuilder ();
161
+ Document errorDocument = documentBuilder .newDocument ();
162
+ Element root = errorDocument .createElemet ("error" );
163
+ errorDocument .appendChild (root );
164
+ Node input = errorDocument .createElement ("reason" );
165
+ input .setTextContent (message );
166
+ root .appendChild (input );
167
+ return errorDocument ;
168
+ } catch (ParserConfigurationException e ) {
169
+ LOGGER .error ("Exception creating document for exception '" + message + "'" , e );
170
+ return null ;
171
+ }
172
+ }
141
173
142
174
@ Override
143
175
public Document createJob (ZencoderJob job )
144
176
throws ZencoderErrorResponseException {
177
+ if (currentConnectionAttempt > MAX_CONNECTION_ATTEMPTS ) {
178
+ resetConnectionCount ();
179
+ String message = "Reached maximum number of connection attempts for Zencoder, aborting creation of job" ;
180
+ Document errorDocument = createDocumentForException (message );
181
+ throw new ZencoderErrorResponseException (errorDocument );
182
+ }
145
183
Document data ;
146
184
try {
147
185
data = job .createXML ();
148
186
if (data == null ) {
149
- LOGGER .error ("Got no XML from Job" );
187
+ String message = "Got no XML from Job" ;
188
+ LOGGER .error (message );
189
+ resetConnectionCount ();
190
+ Document errorDocument = createDocumentForException (message );
191
+ throw new ZencoderErrorResponseException (errorDocument );
150
192
}
151
193
Element apikey = data .createElement ("api_key" );
152
194
apikey .setTextContent (zencoderAPIKey );
153
195
data .getDocumentElement ().appendChild (apikey );
154
196
Document response = sendPostRequest (zencoderAPIBaseUrl
155
197
+ "jobs?format=xml" , data );
198
+ // a null response means the call did not get through
199
+ // we should try again, since the job has not been started
200
+ if (response == null ) {
201
+ currentConnectionAttempt ++;
202
+ // maybe delay this call by a few seconds?
203
+ return createJob (job );
204
+ }
156
205
String id = (String ) xPath .evaluate ("/api-response/job/id" ,
157
206
response , XPathConstants .STRING );
158
207
if (StringUtils .isNotEmpty (id )) {
159
208
job .setJobId (Integer .parseInt (id ));
209
+ resetConnectionCount ();
160
210
return response ;
161
211
}
162
212
completeJobInfo (job , response );
163
213
LOGGER .error ("Error when sending request to Zencoder: " , response );
214
+ resetConnectionCount ();
164
215
throw new ZencoderErrorResponseException (response );
165
216
} catch (ParserConfigurationException e ) {
166
217
LOGGER .error ("Parser threw Exception" , e );
167
218
} catch (XPathExpressionException e ) {
168
219
LOGGER .error ("XPath threw Exception" , e );
169
220
}
221
+ resetConnectionCount ();
170
222
return null ;
171
223
}
172
224
@@ -205,23 +257,47 @@ public Document getJobProgress(ZencoderJob job) {
205
257
}
206
258
207
259
public Document getJobProgress (int id ) {
260
+ if (currentConnectionAttempt > MAX_CONNECTION_ATTEMPTS ) {
261
+ resetConnectionCount ();
262
+ LOGGER .error ("Reached maximum number of attempts for getting job progress. Aborting and returning null" );
263
+ return null ;
264
+ }
208
265
if (zencoderAPIVersion != ZencoderAPIVersion .API_V2 ) {
209
266
LOGGER .warn ("jobProgress is only available for API v2. Returning null." );
210
267
return null ;
211
268
}
212
269
String url = zencoderAPIBaseUrl + "jobs/" + id
213
270
+ "/progress.xml?api_key=" + zencoderAPIKey ;
214
- return sendGetRequest (url );
271
+ Document result = sendGetRequest (url );
272
+ if (result == null ) {
273
+ currentConnectionAttempt ++;
274
+ // delay this call by a few seconds?
275
+ return getJobProgress (id );
276
+ }
277
+ resetConnectionCount ();
278
+ return result ;
215
279
}
216
280
217
281
public Document getJobDetails (ZencoderJob job ) {
218
282
return getJobDetails (job .getJobId ());
219
283
}
220
284
221
285
public Document getJobDetails (int id ) {
286
+ if (currentConnectionAttempt > MAX_CONNECTION_ATTEMPTS ) {
287
+ resetConnectionCount ();
288
+ LOGGER .error ("Reached maximum number of attempts for getting job details. Aborting and returning null" );
289
+ return null ;
290
+ }
222
291
String url = zencoderAPIBaseUrl + "jobs/" + id + ".xml?api_key="
223
292
+ zencoderAPIKey ;
224
- return sendGetRequest (url );
293
+ Document result = sendGetRequest (url );
294
+ if (result == null ) {
295
+ currentConnectionAttempt ++;
296
+ // delay this call by a few seconds?
297
+ return getJobDetails (id );
298
+ }
299
+ resetConnectionCount ();
300
+ return result ;
225
301
}
226
302
227
303
public boolean resubmitJob (ZencoderJob job ) {
@@ -233,10 +309,20 @@ public boolean resubmitJob(ZencoderJob job) {
233
309
}
234
310
235
311
public boolean resubmitJob (int id ) {
312
+ if (currentConnectionAttempt > MAX_CONNECTION_ATTEMPTS ) {
313
+ resetConnectionCount ();
314
+ LOGGER .error ("Reached maximum number of attempts to resubmit job, aborting" );
315
+ return false ;
316
+ }
236
317
String url = zencoderAPIBaseUrl + "jobs/" + id + "/resubmit?api_key="
237
318
+ zencoderAPIKey ;
238
319
ClientResponse response = sendPutRequest (url );
320
+ if (response == null ) {
321
+ currentConnectionAtttempt ++;
322
+ return resubmitJob (id );
323
+ }
239
324
int responseStatus = response .getStatus ();
325
+ resetConnectionCount ();
240
326
if (responseStatus == 200 || responseStatus == 204 ) {
241
327
return true ;
242
328
} else if (responseStatus == 409 ) {
@@ -255,10 +341,20 @@ public boolean cancelJob(ZencoderJob job) {
255
341
}
256
342
257
343
public boolean cancelJob (int id ) {
344
+ if (currentConnectionAttempt > MAX_CONNECTION_ATTEMPTS ) {
345
+ resetConnectionCount ();
346
+ LOGGER .error ("Reached maximum number of attempts to cancel job, aborting" );
347
+ return false ;
348
+ }
258
349
String url = zencoderAPIBaseUrl + "jobs/" + id
259
350
+ "/cancel.json?api_key=" + zencoderAPIKey ;
260
351
ClientResponse res = sendPutRequest (url );
352
+ if (res == null ) {
353
+ currentConnectionAttempt ++;
354
+ return cancelJob (id );
355
+ }
261
356
int responseStatus = res .getStatus ();
357
+ resetConnectionCount ();
262
358
if (responseStatus == 200 || responseStatus == 204 ) {
263
359
return true ;
264
360
} else if (responseStatus == 409 ) {
@@ -292,20 +388,38 @@ public boolean deleteJob(int id) {
292
388
293
389
protected Document sendGetRequest (String url ) {
294
390
LOGGER .debug ("calling: {}" , url );
295
- WebResource webResource = httpClient .resource (url );
296
- Document response = webResource .get (Document .class );
391
+ try {
392
+ WebResource webResource = httpClient .resource (url );
393
+ Document response = webResource .get (Document .class );
297
394
298
- logXmlDocumentToDebug ("Got response" , response );
299
- return response ;
395
+ logXmlDocumentToDebug ("Got response" , response );
396
+ return response ;
397
+ } catch (Exception e ) {
398
+ if (e instanceof SocketTimeoutException ) {
399
+ LOGGER .warn ("Connection to Zencoder timed out" );
400
+ } else {
401
+ LOGGER .warn (e .getMessage ());
402
+ }
403
+ }
404
+ return null ;
300
405
}
301
406
302
407
protected ClientResponse sendPutRequest (String url ) {
303
408
LOGGER .debug ("calling: {}" , url );
304
- WebResource webResource = httpClient .resource (url );
305
- ClientResponse response = webResource .put (ClientResponse .class );
409
+ try {
410
+ WebResource webResource = httpClient .resource (url );
411
+ ClientResponse response = webResource .put (ClientResponse .class );
306
412
307
- LOGGER .debug ("Got response: {}" , response );
308
- return response ;
413
+ LOGGER .debug ("Got response: {}" , response );
414
+ return response ;
415
+ } catch (Exception e ) {
416
+ if (e instanceof SocketTimeoutException ) {
417
+ LOGGER .warn ("Connection to Zencoder timed out" );
418
+ } else {
419
+ LOGGER .warn (e .getMessage ());
420
+ }
421
+ }
422
+ return null ;
309
423
310
424
}
311
425
@@ -331,7 +445,14 @@ protected Document sendPostRequest(String url, Document xml) {
331
445
}
332
446
LOGGER .error ("couldn't submit job: {}" , errormessage );
333
447
return errorXml ;
448
+ } catch (Exception e ) {
449
+ if (e instanceof SocketTimeoutException ) {
450
+ LOGGER .warn ("Connection to Zencoder timed out" );
451
+ } else {
452
+ LOGGER .warn (e .getMessage ());
453
+ }
334
454
}
455
+ return null ;
335
456
336
457
}
337
458
0 commit comments