1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.scheduler.remote;
23
24 import static java.nio.charset.StandardCharsets.UTF_8;
25 import static org.apache.http.HttpStatus.SC_BAD_REQUEST;
26 import static org.apache.http.HttpStatus.SC_CONFLICT;
27 import static org.apache.http.HttpStatus.SC_CREATED;
28 import static org.apache.http.HttpStatus.SC_FORBIDDEN;
29 import static org.apache.http.HttpStatus.SC_NOT_FOUND;
30 import static org.apache.http.HttpStatus.SC_NO_CONTENT;
31 import static org.apache.http.HttpStatus.SC_OK;
32 import static org.apache.http.HttpStatus.SC_UNAUTHORIZED;
33
34 import org.opencastproject.mediapackage.MediaPackage;
35 import org.opencastproject.mediapackage.MediaPackageParser;
36 import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
37 import org.opencastproject.metadata.dublincore.DublinCores;
38 import org.opencastproject.scheduler.api.Recording;
39 import org.opencastproject.scheduler.api.RecordingImpl;
40 import org.opencastproject.scheduler.api.SchedulerConflictException;
41 import org.opencastproject.scheduler.api.SchedulerException;
42 import org.opencastproject.scheduler.api.SchedulerService;
43 import org.opencastproject.scheduler.api.TechnicalMetadata;
44 import org.opencastproject.scheduler.api.TechnicalMetadataImpl;
45 import org.opencastproject.security.api.TrustedHttpClient;
46 import org.opencastproject.security.api.UnauthorizedException;
47 import org.opencastproject.serviceregistry.api.RemoteBase;
48 import org.opencastproject.serviceregistry.api.ServiceRegistry;
49 import org.opencastproject.util.DateTimeSupport;
50 import org.opencastproject.util.NotFoundException;
51 import org.opencastproject.util.UrlSupport;
52
53 import com.entwinemedia.fn.data.Opt;
54
55 import net.fortuna.ical4j.model.Period;
56 import net.fortuna.ical4j.model.property.RRule;
57
58 import org.apache.commons.lang3.BooleanUtils;
59 import org.apache.commons.lang3.StringUtils;
60 import org.apache.http.HttpResponse;
61 import org.apache.http.NameValuePair;
62 import org.apache.http.client.entity.UrlEncodedFormEntity;
63 import org.apache.http.client.methods.HttpDelete;
64 import org.apache.http.client.methods.HttpGet;
65 import org.apache.http.client.methods.HttpPost;
66 import org.apache.http.client.methods.HttpPut;
67 import org.apache.http.client.utils.URLEncodedUtils;
68 import org.apache.http.message.BasicNameValuePair;
69 import org.apache.http.util.EntityUtils;
70 import org.json.simple.JSONArray;
71 import org.json.simple.JSONObject;
72 import org.json.simple.parser.JSONParser;
73 import org.osgi.service.component.annotations.Component;
74 import org.osgi.service.component.annotations.Reference;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77
78 import java.util.ArrayList;
79 import java.util.Collections;
80 import java.util.Date;
81 import java.util.HashMap;
82 import java.util.HashSet;
83 import java.util.List;
84 import java.util.Map;
85 import java.util.Map.Entry;
86 import java.util.Properties;
87 import java.util.Set;
88 import java.util.TimeZone;
89
90
91
92
93 @Component(
94 immediate = true,
95 service = SchedulerService.class,
96 property = {
97 "service.description=Scheduler Remote Service Proxy"
98 }
99 )
100 public class SchedulerServiceRemoteImpl extends RemoteBase implements SchedulerService {
101
102 private static final Logger logger = LoggerFactory.getLogger(SchedulerServiceRemoteImpl.class);
103
104
105 private final JSONParser parser = new JSONParser();
106
107 public SchedulerServiceRemoteImpl() {
108 super(JOB_TYPE);
109 }
110
111 @Override
112 public void addEvent(Date startDateTime, Date endDateTime, String captureAgentId, Set<String> userIds,
113 MediaPackage mediaPackage, Map<String, String> wfProperties, Map<String, String> caMetadata,
114 Opt<String> schedulingSource) throws UnauthorizedException, SchedulerConflictException,
115 SchedulerException {
116 HttpPost post = new HttpPost("/");
117 String eventId = mediaPackage.getIdentifier().toString();
118 logger.debug("Start adding a new event {} through remote Schedule Service", eventId);
119
120 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
121 params.add(new BasicNameValuePair("start", Long.toString(startDateTime.getTime())));
122 params.add(new BasicNameValuePair("end", Long.toString(endDateTime.getTime())));
123 params.add(new BasicNameValuePair("agent", captureAgentId));
124 params.add(new BasicNameValuePair("users", StringUtils.join(userIds, ",")));
125 params.add(new BasicNameValuePair("mediaPackage", MediaPackageParser.getAsXml(mediaPackage)));
126 params.add(new BasicNameValuePair("wfproperties", toPropertyString(wfProperties)));
127 params.add(new BasicNameValuePair("agentparameters", toPropertyString(caMetadata)));
128 if (schedulingSource.isSome())
129 params.add(new BasicNameValuePair("source", schedulingSource.get()));
130 post.setEntity(new UrlEncodedFormEntity(params, UTF_8));
131
132 HttpResponse response = getResponse(post, SC_CREATED, SC_UNAUTHORIZED, SC_CONFLICT);
133 try {
134 if (response != null && SC_CREATED == response.getStatusLine().getStatusCode()) {
135 logger.info("Successfully added event {} to the scheduler service", eventId);
136 return;
137 } else if (response != null && SC_CONFLICT == response.getStatusLine().getStatusCode()) {
138 String errorJson = EntityUtils.toString(response.getEntity(), UTF_8);
139 JSONObject json = (JSONObject) parser.parse(errorJson);
140 JSONObject error = (JSONObject) json.get("error");
141 String errorCode = (String) error.get("code");
142 if (SchedulerConflictException.ERROR_CODE.equals(errorCode)) {
143 logger.info("Conflicting events found when adding event {}", eventId);
144 throw new SchedulerConflictException("Conflicting events found when adding event " + eventId);
145 } else {
146 throw new SchedulerException("Unexpected error code " + errorCode);
147 }
148 } else if (response != null && SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
149 logger.info("Unauthorized to create the event");
150 throw new UnauthorizedException("Unauthorized to create the event");
151 } else {
152 throw new SchedulerException("Unable to add event " + eventId + " to the scheduler service");
153 }
154 } catch (UnauthorizedException | SchedulerConflictException e) {
155 throw e;
156 } catch (Exception e) {
157 throw new SchedulerException("Unable to add event " + eventId + " to the scheduler service", e);
158 } finally {
159 closeConnection(response);
160 }
161 }
162
163 @Override
164 public Map<String, Period> addMultipleEvents(RRule rRule, Date start, Date end, Long duration, TimeZone tz,
165 String captureAgentId, Set<String> userIds, MediaPackage templateMp, Map<String, String> wfProperties,
166 Map<String, String> caMetadata, Opt<String> schedulingSource)
167 throws UnauthorizedException, SchedulerConflictException, SchedulerException {
168 HttpPost post = new HttpPost("/");
169 logger.debug("Start adding a new events through remote Schedule Service");
170
171 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
172 params.add(new BasicNameValuePair("rrule", rRule.getValue()));
173 params.add(new BasicNameValuePair("start", Long.toString(start.getTime())));
174 params.add(new BasicNameValuePair("end", Long.toString(end.getTime())));
175 params.add(new BasicNameValuePair("duration", Long.toString(duration)));
176 params.add(new BasicNameValuePair("tz", tz.toZoneId().getId()));
177 params.add(new BasicNameValuePair("agent", captureAgentId));
178 params.add(new BasicNameValuePair("users", StringUtils.join(userIds, ",")));
179 params.add(new BasicNameValuePair("templateMp", MediaPackageParser.getAsXml(templateMp)));
180 params.add(new BasicNameValuePair("wfproperties", toPropertyString(wfProperties)));
181 params.add(new BasicNameValuePair("agentparameters", toPropertyString(caMetadata)));
182 if (schedulingSource.isSome())
183 params.add(new BasicNameValuePair("source", schedulingSource.get()));
184 post.setEntity(new UrlEncodedFormEntity(params, UTF_8));
185
186 String eventId = templateMp.getIdentifier().toString();
187
188 HttpResponse response = getResponse(post, SC_CREATED, SC_UNAUTHORIZED, SC_CONFLICT);
189 try {
190 if (response != null && SC_CREATED == response.getStatusLine().getStatusCode()) {
191 logger.info("Successfully added events to the scheduler service");
192 return null;
193 } else if (response != null && SC_CONFLICT == response.getStatusLine().getStatusCode()) {
194 String errorJson = EntityUtils.toString(response.getEntity(), UTF_8);
195 JSONObject json = (JSONObject) parser.parse(errorJson);
196 JSONObject error = (JSONObject) json.get("error");
197 String errorCode = (String) error.get("code");
198 if (SchedulerConflictException.ERROR_CODE.equals(errorCode)) {
199 logger.info("Conflicting events found when adding event based on {}", eventId);
200 throw new SchedulerConflictException("Conflicting events found when adding event based on" + eventId);
201 } else {
202 throw new SchedulerException("Unexpected error code " + errorCode);
203 }
204 } else if (response != null && SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
205 logger.info("Unauthorized to create the event");
206 throw new UnauthorizedException("Unauthorized to create the event");
207 } else {
208 throw new SchedulerException("Unable to add event " + eventId + " to the scheduler service");
209 }
210 } catch (UnauthorizedException | SchedulerConflictException e) {
211 throw e;
212 } catch (Exception e) {
213 throw new SchedulerException("Unable to add event " + eventId + " to the scheduler service", e);
214 } finally {
215 closeConnection(response);
216 }
217 }
218
219 @Override
220 public void updateEvent(String eventId, Opt<Date> startDateTime, Opt<Date> endDateTime, Opt<String> captureAgentId,
221 Opt<Set<String>> userIds, Opt<MediaPackage> mediaPackage, Opt<Map<String, String>> wfProperties,
222 Opt<Map<String, String>> caMetadata)
223 throws NotFoundException, UnauthorizedException, SchedulerConflictException, SchedulerException {
224
225 updateEvent(eventId, startDateTime, endDateTime, captureAgentId, userIds,
226 mediaPackage, wfProperties, caMetadata, false);
227 }
228
229 @Override
230 public void updateEvent(String eventId, Opt<Date> startDateTime, Opt<Date> endDateTime, Opt<String> captureAgentId,
231 Opt<Set<String>> userIds, Opt<MediaPackage> mediaPackage, Opt<Map<String, String>> wfProperties,
232 Opt<Map<String, String>> caMetadata, boolean allowConflict)
233 throws NotFoundException, UnauthorizedException, SchedulerConflictException, SchedulerException {
234
235 logger.debug("Start updating event {}.", eventId);
236 HttpPut put = new HttpPut("/" + eventId);
237
238 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
239 if (startDateTime.isSome())
240 params.add(new BasicNameValuePair("start", Long.toString(startDateTime.get().getTime())));
241 if (endDateTime.isSome())
242 params.add(new BasicNameValuePair("end", Long.toString(endDateTime.get().getTime())));
243 if (captureAgentId.isSome())
244 params.add(new BasicNameValuePair("agent", captureAgentId.get()));
245 if (userIds.isSome())
246 params.add(new BasicNameValuePair("users", StringUtils.join(userIds.get(), ",")));
247 if (mediaPackage.isSome())
248 params.add(new BasicNameValuePair("mediaPackage", MediaPackageParser.getAsXml(mediaPackage.get())));
249 if (wfProperties.isSome())
250 params.add(new BasicNameValuePair("wfproperties", toPropertyString(wfProperties.get())));
251 if (caMetadata.isSome())
252 params.add(new BasicNameValuePair("agentparameters", toPropertyString(caMetadata.get())));
253 params.add(new BasicNameValuePair("allowConflict", BooleanUtils.toString(allowConflict, "true", "false", "false")));
254 put.setEntity(new UrlEncodedFormEntity(params, UTF_8));
255
256 HttpResponse response = getResponse(put, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED, SC_FORBIDDEN, SC_CONFLICT);
257 try {
258 if (response != null) {
259 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
260 logger.info("Event {} was not found by the scheduler service", eventId);
261 throw new NotFoundException("Event '" + eventId + "' not found on remote scheduler service!");
262 } else if (SC_OK == response.getStatusLine().getStatusCode()) {
263 logger.info("Event {} successfully updated with capture agent metadata.", eventId);
264 return;
265 } else if (response != null && SC_CONFLICT == response.getStatusLine().getStatusCode()) {
266 String errorJson = EntityUtils.toString(response.getEntity(), UTF_8);
267 JSONObject json = (JSONObject) parser.parse(errorJson);
268 JSONObject error = (JSONObject) json.get("error");
269 String errorCode = (String) error.get("code");
270 if (SchedulerConflictException.ERROR_CODE.equals(errorCode)) {
271 logger.info("Conflicting events found when updating event {}", eventId);
272 throw new SchedulerConflictException("Conflicting events found when updating event " + eventId);
273 } else {
274 throw new SchedulerException("Unexpected error code " + errorCode);
275 }
276 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
277 logger.info("Unauthorized to update the event {}.", eventId);
278 throw new UnauthorizedException("Unauthorized to update the event " + eventId);
279 } else if (SC_FORBIDDEN == response.getStatusLine().getStatusCode()) {
280 logger.info("Forbidden to update the event {}.", eventId);
281 throw new SchedulerException("Event with specified ID cannot be updated");
282 } else {
283 throw new SchedulerException("Unexpected status code " + response.getStatusLine());
284 }
285 }
286 } catch (NotFoundException | SchedulerConflictException | UnauthorizedException e) {
287 throw e;
288 } catch (Exception e) {
289 throw new SchedulerException("Unable to update event " + eventId + " to the scheduler service", e);
290 } finally {
291 closeConnection(response);
292 }
293 throw new SchedulerException("Unable to update event " + eventId);
294 }
295
296 @Override
297 public void removeEvent(String eventId) throws NotFoundException, UnauthorizedException, SchedulerException {
298 logger.debug("Start removing event {} from scheduling service.", eventId);
299 HttpDelete delete = new HttpDelete("/" + eventId);
300
301 HttpResponse response = getResponse(delete, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED, SC_CONFLICT);
302 try {
303 if (response != null && SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
304 logger.info("Event {} was not found by the scheduler service", eventId);
305 throw new NotFoundException("Event '" + eventId + "' not found on remote scheduler service!");
306 } else if (response != null && SC_OK == response.getStatusLine().getStatusCode()) {
307 logger.info("Event {} removed from scheduling service.", eventId);
308 return;
309 } else if (response != null && SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
310 logger.info("Unauthorized to remove the event {}.", eventId);
311 throw new UnauthorizedException("Unauthorized to remove the event " + eventId);
312 }
313 } catch (UnauthorizedException | NotFoundException e) {
314 throw e;
315 } catch (Exception e) {
316 throw new SchedulerException("Unable to remove event " + eventId + " from the scheduler service", e);
317 } finally {
318 closeConnection(response);
319 }
320 throw new SchedulerException("Unable to remove event " + eventId);
321 }
322
323 @Override
324 public MediaPackage getMediaPackage(String eventId)
325 throws NotFoundException, UnauthorizedException, SchedulerException {
326 HttpGet get = new HttpGet(eventId.concat("/mediapackage.xml"));
327 HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
328 try {
329 if (response != null) {
330 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
331 throw new NotFoundException("Event mediapackage '" + eventId + "' not found on remote scheduler service!");
332 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
333 logger.info("Unauthorized to get mediapacakge of the event {}.", eventId);
334 throw new UnauthorizedException("Unauthorized to get mediapackage of the event " + eventId);
335 } else {
336 MediaPackage mp = MediaPackageParser.getFromXml(EntityUtils.toString(response.getEntity(), UTF_8));
337 logger.info("Successfully get event mediapackage {} from the remote scheduler service", eventId);
338 return mp;
339 }
340 }
341 } catch (NotFoundException e) {
342 throw e;
343 } catch (UnauthorizedException e) {
344 throw e;
345 } catch (Exception e) {
346 throw new SchedulerException("Unable to parse event media package from remote scheduler service", e);
347 } finally {
348 closeConnection(response);
349 }
350 throw new SchedulerException("Unable to get event media package from remote scheduler service");
351 }
352
353 @Override
354 public DublinCoreCatalog getDublinCore(String eventId)
355 throws NotFoundException, UnauthorizedException, SchedulerException {
356 HttpGet get = new HttpGet(eventId.concat("/dublincore.xml"));
357 HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
358 try {
359 if (response != null) {
360 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
361 throw new NotFoundException("Event catalog '" + eventId + "' not found on remote scheduler service!");
362 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
363 logger.info("Unauthorized to get dublincore of the event {}.", eventId);
364 throw new UnauthorizedException("Unauthorized to get dublincore of the event " + eventId);
365 } else {
366 DublinCoreCatalog dublinCoreCatalog = DublinCores.read(response.getEntity().getContent());
367 logger.info("Successfully get event dublincore {} from the remote scheduler service", eventId);
368 return dublinCoreCatalog;
369 }
370 }
371 } catch (NotFoundException | UnauthorizedException e) {
372 throw e;
373 } catch (Exception e) {
374 throw new SchedulerException("Unable to parse event dublincore from remote scheduler service", e);
375 } finally {
376 closeConnection(response);
377 }
378 throw new SchedulerException("Unable to get event dublincore from remote scheduler service");
379 }
380
381 @Override
382 public TechnicalMetadata getTechnicalMetadata(String eventId)
383 throws NotFoundException, UnauthorizedException, SchedulerException {
384 HttpGet get = new HttpGet(eventId.concat("/technical.json"));
385 HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
386 try {
387 if (response != null) {
388 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
389 throw new NotFoundException("Event with id '" + eventId + "' not found on remote scheduler service!");
390 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
391 logger.info("Unauthorized to get the technical metadata of the event {}.", eventId);
392 throw new UnauthorizedException("Unauthorized to get the technical metadata of the event " + eventId);
393 } else {
394 String technicalMetadataJson = EntityUtils.toString(response.getEntity(), UTF_8);
395 JSONObject json = (JSONObject) parser.parse(technicalMetadataJson);
396 final String recordingId = (String) json.get("id");
397 final Date start = new Date(DateTimeSupport.fromUTC((String) json.get("start")));
398 final Date end = new Date(DateTimeSupport.fromUTC((String) json.get("end")));
399 final String location = (String) json.get("location");
400
401 final Set<String> presenters = new HashSet<>();
402 JSONArray presentersArr = (JSONArray) json.get("presenters");
403 for (int i = 0; i < presentersArr.size(); i++) {
404 presenters.add((String) presentersArr.get(i));
405 }
406
407 final Map<String, String> wfProperties = new HashMap<>();
408 JSONObject wfPropertiesObj = (JSONObject) json.get("wfProperties");
409 Set<Entry<String, String>> entrySet = wfPropertiesObj.entrySet();
410 for (Entry<String, String> entry : entrySet) {
411 wfProperties.put(entry.getKey(), entry.getValue());
412 }
413
414 final Map<String, String> agentConfig = new HashMap<>();
415 JSONObject agentConfigObj = (JSONObject) json.get("agentConfig");
416 entrySet = agentConfigObj.entrySet();
417 for (Entry<String, String> entry : entrySet) {
418 agentConfig.put(entry.getKey(), entry.getValue());
419 }
420
421 String status = (String) json.get("state");
422 String lastHeard = (String) json.get("lastHeardFrom");
423 Recording recording = null;
424 if (StringUtils.isNotBlank(status) && StringUtils.isNotBlank(lastHeard)) {
425 recording = new RecordingImpl(recordingId, status, DateTimeSupport.fromUTC(lastHeard));
426 }
427 final Opt<Recording> recordingOpt = Opt.nul(recording);
428 logger.info("Successfully get the technical metadata of event '{}' from the remote scheduler service",
429 eventId);
430 return new TechnicalMetadataImpl(recordingId, location, start, end, presenters, wfProperties,
431 agentConfig, recordingOpt);
432 }
433 }
434 } catch (NotFoundException | UnauthorizedException e) {
435 throw e;
436 } catch (Exception e) {
437 throw new SchedulerException("Unable to parse the technical metadata from remote scheduler service", e);
438 } finally {
439 closeConnection(response);
440 }
441 throw new SchedulerException("Unable to get the technical metadata from remote scheduler service");
442 }
443
444 @Override
445 public Map<String, String> getWorkflowConfig(String eventId)
446 throws NotFoundException, UnauthorizedException, SchedulerException {
447 HttpGet get = new HttpGet(eventId.concat("/workflow.properties"));
448 HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
449 try {
450 if (response != null) {
451 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
452 throw new NotFoundException(
453 "Event workflow configuration '" + eventId + "' not found on remote scheduler service!");
454 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
455 logger.info("Unauthorized to get workflow config of the event {}.", eventId);
456 throw new UnauthorizedException("Unauthorized to get workflow config of the event " + eventId);
457 } else {
458 Properties properties = new Properties();
459 properties.load(response.getEntity().getContent());
460 logger.info("Successfully get event workflow configuration {} from the remote scheduler service", eventId);
461 return new HashMap<String, String>((Map) properties);
462 }
463 }
464 } catch (NotFoundException | UnauthorizedException e) {
465 throw e;
466 } catch (Exception e) {
467 throw new SchedulerException("Unable to parse event workflow configuration from remote scheduler service", e);
468 } finally {
469 closeConnection(response);
470 }
471 throw new SchedulerException("Unable to get event workflow configuration from remote scheduler service");
472 }
473
474 @Override
475 public Map<String, String> getCaptureAgentConfiguration(String eventId)
476 throws NotFoundException, UnauthorizedException, SchedulerException {
477 HttpGet get = new HttpGet(eventId.concat("/agent.properties"));
478 HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
479 try {
480 if (response != null) {
481 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
482 throw new NotFoundException(
483 "Event capture agent configuration '" + eventId + "' not found on remote scheduler service!");
484 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
485 logger.info("Unauthorized to get capture agent config of the event {}.", eventId);
486 throw new UnauthorizedException("Unauthorized to get capture agent config of the event " + eventId);
487 } else {
488 Properties properties = new Properties();
489 properties.load(response.getEntity().getContent());
490 logger.info("Successfully get event capture agent configuration {} from the remote scheduler service",
491 eventId);
492 return new HashMap<String, String>((Map) properties);
493 }
494 }
495 } catch (NotFoundException | UnauthorizedException e) {
496 throw e;
497 } catch (Exception e) {
498 throw new SchedulerException(
499 "Unable to parse event capture agent configuration from remote scheduler service", e);
500 } finally {
501 closeConnection(response);
502 }
503 throw new SchedulerException("Unable to get event capture agent configuration from remote scheduler service");
504 }
505
506 @Override
507 public int getEventCount() throws SchedulerException, UnauthorizedException {
508 final HttpGet get = new HttpGet(UrlSupport.concat("eventCount"));
509 final HttpResponse response = getResponse(get, SC_OK, SC_UNAUTHORIZED);
510 try {
511 if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
512 logger.info("Unauthorized to get event count");
513 throw new UnauthorizedException("Unauthorized to get event count");
514 }
515 final String countString = EntityUtils.toString(response.getEntity(), UTF_8);
516 return Integer.parseInt(countString);
517 } catch (UnauthorizedException e) {
518 throw e;
519 } catch (Exception e) {
520 throw new SchedulerException("Unable to get event count from remote scheduler service", e);
521 } finally {
522 closeConnection(response);
523 }
524 }
525
526 @Override
527 public String getScheduleLastModified(String agentId) throws SchedulerException {
528 HttpGet get = new HttpGet(UrlSupport.concat(agentId, "lastmodified"));
529 HttpResponse response = getResponse(get, SC_OK);
530 try {
531 if (response != null) {
532 if (SC_OK == response.getStatusLine().getStatusCode()) {
533 String agentHash = EntityUtils.toString(response.getEntity(), UTF_8);
534 logger.info("Successfully get agent last modified hash of agent with id {} from the remote scheduler service",
535 agentId);
536 return agentHash;
537 }
538 }
539 } catch (Exception e) {
540 throw new SchedulerException("Unable to get agent last modified hash from remote scheduler service", e);
541 } finally {
542 closeConnection(response);
543 }
544 throw new SchedulerException("Unable to get agent last modified hash from remote scheduler service");
545 }
546
547 @Override
548 public List<MediaPackage> search(Opt<String> captureAgentId, Opt<Date> startsFrom, Opt<Date> startsTo,
549 Opt<Date> endFrom, Opt<Date> endTo) throws UnauthorizedException, SchedulerException {
550 List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>();
551 for (String s : captureAgentId) {
552 queryStringParams.add(new BasicNameValuePair("agent", s));
553 }
554 for (Date d : startsFrom) {
555 queryStringParams.add(new BasicNameValuePair("startsfrom", Long.toString(d.getTime())));
556 }
557 for (Date d : startsTo) {
558 queryStringParams.add(new BasicNameValuePair("startsto", Long.toString(d.getTime())));
559 }
560 for (Date d : endFrom) {
561 queryStringParams.add(new BasicNameValuePair("endsfrom", Long.toString(d.getTime())));
562 }
563 for (Date d : endTo) {
564 queryStringParams.add(new BasicNameValuePair("endsto", Long.toString(d.getTime())));
565 }
566 HttpGet get = new HttpGet("recordings.xml?".concat(URLEncodedUtils.format(queryStringParams, UTF_8)));
567 HttpResponse response = getResponse(get, SC_OK, SC_UNAUTHORIZED);
568 try {
569 if (response != null) {
570 if (SC_OK == response.getStatusLine().getStatusCode()) {
571 String mediaPackageXml = EntityUtils.toString(response.getEntity(), UTF_8);
572 List<MediaPackage> events = MediaPackageParser.getArrayFromXml(mediaPackageXml);
573 logger.info("Successfully get recordings from the remote scheduler service");
574 return events;
575 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
576 logger.info("Unauthorized to search for events");
577 throw new UnauthorizedException("Unauthorized to search for events");
578 }
579 }
580 } catch (UnauthorizedException e) {
581 throw e;
582 } catch (Exception e) {
583 throw new SchedulerException("Unable to get recordings from remote scheduler service", e);
584 } finally {
585 closeConnection(response);
586 }
587 throw new SchedulerException("Unable to get recordings from remote scheduler service");
588 }
589
590 @Override
591 public Opt<MediaPackage> getCurrentRecording(String captureAgentId) throws SchedulerException, UnauthorizedException {
592 HttpGet get = new HttpGet(UrlSupport.concat("currentRecording", captureAgentId));
593 HttpResponse response = getResponse(get, SC_OK, SC_NO_CONTENT, SC_UNAUTHORIZED);
594 try {
595 if (SC_OK == response.getStatusLine().getStatusCode()) {
596 String mediaPackageXml = EntityUtils.toString(response.getEntity(), UTF_8);
597 MediaPackage event = MediaPackageParser.getFromXml(mediaPackageXml);
598 logger.info("Successfully get current recording of agent {} from the remote scheduler service", captureAgentId);
599 return Opt.some(event);
600 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
601 logger.info("Unauthorized to get current recording of agent {}", captureAgentId);
602 throw new UnauthorizedException("Unauthorized to get current recording of agent " + captureAgentId);
603 } else {
604 return Opt.none();
605 }
606 } catch (UnauthorizedException e) {
607 throw e;
608 } catch (Exception e) {
609 throw new SchedulerException("Unable to get current recording from remote scheduler service", e);
610 } finally {
611 closeConnection(response);
612 }
613 }
614
615 @Override
616 public Opt<MediaPackage> getUpcomingRecording(String captureAgentId) throws SchedulerException, UnauthorizedException {
617 HttpGet get = new HttpGet(UrlSupport.concat("upcomingRecording", captureAgentId));
618 HttpResponse response = getResponse(get, SC_OK, SC_NO_CONTENT, SC_UNAUTHORIZED);
619 try {
620 if (SC_OK == response.getStatusLine().getStatusCode()) {
621 String mediaPackageXml = EntityUtils.toString(response.getEntity(), UTF_8);
622 MediaPackage event = MediaPackageParser.getFromXml(mediaPackageXml);
623 logger.info("Successfully get upcoming recording of agent {} from the remote scheduler service", captureAgentId);
624 return Opt.some(event);
625 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
626 logger.info("Unauthorized to get upcoming recording of agent {}", captureAgentId);
627 throw new UnauthorizedException("Unauthorized to get upcoming recording of agent " + captureAgentId);
628 } else {
629 return Opt.none();
630 }
631 } catch (UnauthorizedException e) {
632 throw e;
633 } catch (Exception e) {
634 throw new SchedulerException("Unable to get upcoming recording from remote scheduler service", e);
635 } finally {
636 closeConnection(response);
637 }
638 }
639
640 @Override
641 public List<MediaPackage> findConflictingEvents(String captureDeviceID, Date startDate, Date endDate)
642 throws UnauthorizedException, SchedulerException {
643 List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>();
644 queryStringParams.add(new BasicNameValuePair("agent", captureDeviceID));
645 queryStringParams.add(new BasicNameValuePair("start", Long.toString(startDate.getTime())));
646 queryStringParams.add(new BasicNameValuePair("end", Long.toString(endDate.getTime())));
647 HttpGet get = new HttpGet("conflicts.xml?".concat(URLEncodedUtils.format(queryStringParams, UTF_8)));
648 HttpResponse response = getResponse(get, SC_OK, SC_NO_CONTENT);
649 try {
650 if (response != null) {
651 if (SC_OK == response.getStatusLine().getStatusCode()) {
652 String mediaPackageXml = EntityUtils.toString(response.getEntity(), UTF_8);
653 List<MediaPackage> events = MediaPackageParser.getArrayFromXml(mediaPackageXml);
654 logger.info("Successfully get conflicts from the remote scheduler service");
655 return events;
656 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
657 logger.info("Unauthorized to search for conflicting events");
658 throw new UnauthorizedException("Unauthorized to search for conflicting events");
659 } else if (SC_NO_CONTENT == response.getStatusLine().getStatusCode()) {
660 return Collections.<MediaPackage> emptyList();
661 }
662 }
663 } catch (UnauthorizedException e) {
664 throw e;
665 } catch (Exception e) {
666 throw new SchedulerException("Unable to get conflicts from remote scheduler service", e);
667 } finally {
668 closeConnection(response);
669 }
670 throw new SchedulerException("Unable to get conflicts from remote scheduler service");
671 }
672
673 @Override
674 public List<MediaPackage> findConflictingEvents(String captureAgentId, RRule rrule, Date startDate, Date endDate,
675 long duration, TimeZone timezone) throws UnauthorizedException, SchedulerException {
676 List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>();
677 queryStringParams.add(new BasicNameValuePair("agent", captureAgentId));
678 queryStringParams.add(new BasicNameValuePair("rrule", rrule.getRecur().toString()));
679 queryStringParams.add(new BasicNameValuePair("start", Long.toString(startDate.getTime())));
680 queryStringParams.add(new BasicNameValuePair("end", Long.toString(endDate.getTime())));
681 queryStringParams.add(new BasicNameValuePair("duration", Long.toString(duration)));
682 queryStringParams.add(new BasicNameValuePair("timezone", timezone.getID()));
683 HttpGet get = new HttpGet("conflicts.xml?".concat(URLEncodedUtils.format(queryStringParams, UTF_8)));
684 HttpResponse response = getResponse(get, SC_OK, SC_NO_CONTENT);
685 try {
686 if (response != null) {
687 if (SC_OK == response.getStatusLine().getStatusCode()) {
688 String mediaPackageXml = EntityUtils.toString(response.getEntity(), UTF_8);
689 List<MediaPackage> events = MediaPackageParser.getArrayFromXml(mediaPackageXml);
690 logger.info("Successfully get conflicts from the remote scheduler service");
691 return events;
692 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
693 logger.info("Unauthorized to search for conflicting events");
694 throw new UnauthorizedException("Unauthorized to search for conflicting events");
695 } else if (SC_NO_CONTENT == response.getStatusLine().getStatusCode()) {
696 return Collections.<MediaPackage> emptyList();
697 }
698 }
699 } catch (UnauthorizedException e) {
700 throw e;
701 } catch (Exception e) {
702 throw new SchedulerException("Unable to get conflicts from remote scheduler service", e);
703 } finally {
704 closeConnection(response);
705 }
706 throw new SchedulerException("Unable to get conflicts from remote scheduler service");
707 }
708
709 @Override
710 public String getCalendar(Opt<String> captureAgentId, Opt<String> seriesId, Opt<Date> cutoff)
711 throws SchedulerException {
712 List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>();
713 for (String s : captureAgentId) {
714 queryStringParams.add(new BasicNameValuePair("agentid", s));
715 }
716 for (String s : seriesId) {
717 queryStringParams.add(new BasicNameValuePair("seriesid", s));
718 }
719 for (Date d : cutoff) {
720 queryStringParams.add(new BasicNameValuePair("cutoff", Long.toString(d.getTime())));
721 }
722 HttpGet get = new HttpGet("calendars?".concat(URLEncodedUtils.format(queryStringParams, UTF_8)));
723 HttpResponse response = getResponse(get, SC_OK);
724 try {
725 if (response != null) {
726 if (SC_OK == response.getStatusLine().getStatusCode()) {
727 String calendar = EntityUtils.toString(response.getEntity(), UTF_8);
728 logger.info("Successfully get calendar of agent with id {} from the remote scheduler service",
729 captureAgentId);
730 return calendar;
731 }
732 }
733 } catch (Exception e) {
734 throw new SchedulerException("Unable to get calendar from remote scheduler service", e);
735 } finally {
736 closeConnection(response);
737 }
738 throw new SchedulerException("Unable to get calendar from remote scheduler service");
739 }
740
741 @Override
742 public void removeScheduledRecordingsBeforeBuffer(long buffer) throws UnauthorizedException, SchedulerException {
743 HttpPost post = new HttpPost("/removeOldScheduledRecordings");
744 logger.debug("Start removing old schedules before buffer {} through remote Schedule Service", buffer);
745
746 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
747 params.add(new BasicNameValuePair("buffer", Long.toString(buffer)));
748 post.setEntity(new UrlEncodedFormEntity(params, UTF_8));
749
750 HttpResponse response = getResponse(post, SC_OK, SC_UNAUTHORIZED);
751 try {
752 if (response != null && SC_OK == response.getStatusLine().getStatusCode()) {
753 logger.info("Successfully started removing old schedules before butter {} to the scheduler service", buffer);
754 return;
755 } else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
756 logger.info("Unauthorized to remove old schedules before buffer {}.", buffer);
757 throw new UnauthorizedException("Unauthorized to remove old schedules");
758 }
759 } catch (UnauthorizedException e) {
760 throw e;
761 } catch (Exception e) {
762 throw new SchedulerException("Unable to remove old schedules from the scheduler service", e);
763 } finally {
764 closeConnection(response);
765 }
766 throw new SchedulerException("Unable to remove old schedules from the scheduler service");
767 }
768
769 @Override
770 public boolean updateRecordingState(String mediapackageId, String state)
771 throws NotFoundException, SchedulerException {
772 HttpPut put = new HttpPut(UrlSupport.concat(mediapackageId, "recordingStatus"));
773
774 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
775 params.add(new BasicNameValuePair("state", state));
776 put.setEntity(new UrlEncodedFormEntity(params, UTF_8));
777
778 HttpResponse response = getResponse(put, SC_OK, SC_NOT_FOUND, SC_BAD_REQUEST);
779 try {
780 if (response != null) {
781 if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
782 logger.warn("Event with mediapackage id {} was not found by the scheduler service", mediapackageId);
783 throw new NotFoundException(
784 "Event with mediapackage id '" + mediapackageId + "' not found on remote scheduler service!");
785 } else if (SC_BAD_REQUEST == response.getStatusLine().getStatusCode()) {
786 logger.info("Unable to update event with mediapackage id {}, invalid recording state: {}.", mediapackageId,
787 state);
788 return false;
789 } else if (SC_OK == response.getStatusLine().getStatusCode()) {
790 logger.info("Event with mediapackage id {} successfully updated with recording status.", mediapackageId);
791 return true;
792 } else {
793 throw new SchedulerException("Unexpected status code " + response.getStatusLine());
794 }
795 }
796 } catch (NotFoundException e) {
797 throw e;
798 } catch (Exception e) {
799 throw new SchedulerException("Unable to update recording state of event with mediapackage id " + mediapackageId
800 + " to the scheduler service", e);
801 } finally {
802 closeConnection(response);
803 }
804 throw new SchedulerException("Unable to update recording state of event with mediapackage id " + mediapackageId);
805 }
806
807 @Override
808 public Recording getRecordingState(String id) throws NotFoundException, SchedulerException {
809 HttpGet get = new HttpGet(UrlSupport.concat(id, "recordingStatus"));
810 HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND);
811 try {
812 if (response != null) {
813 if (SC_OK == response.getStatusLine().getStatusCode()) {
814 String recordingStateJson = EntityUtils.toString(response.getEntity(), UTF_8);
815 JSONObject json = (JSONObject) parser.parse(recordingStateJson);
816 String recordingId = (String) json.get("id");
817 String status = (String) json.get("state");
818 Long lastHeard = (Long) json.get("lastHeardFrom");
819 logger.info("Successfully get calendar of agent with id {} from the remote scheduler service", id);
820 return new RecordingImpl(recordingId, status, lastHeard);
821 } else if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
822 logger.warn("Event with mediapackage id {} was not found by the scheduler service", id);
823 throw new NotFoundException("Event with mediapackage id '" + id + "' not found on remote scheduler service!");
824 }
825 }
826 } catch (NotFoundException e) {
827 throw e;
828 } catch (Exception e) {
829 throw new SchedulerException("Unable to get calendar from remote scheduler service", e);
830 } finally {
831 closeConnection(response);
832 }
833 throw new SchedulerException("Unable to get calendar from remote scheduler service");
834 }
835
836 @Override
837 public void removeRecording(String eventId) throws NotFoundException, SchedulerException {
838 HttpDelete delete = new HttpDelete(UrlSupport.concat(eventId, "recordingStatus"));
839
840 HttpResponse response = getResponse(delete, SC_OK, SC_NOT_FOUND);
841 try {
842 if (response != null && SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
843 logger.info("Event {} was not found by the scheduler service", eventId);
844 throw new NotFoundException("Event '" + eventId + "' not found on remote scheduler service!");
845 } else if (response != null && SC_OK == response.getStatusLine().getStatusCode()) {
846 logger.info("Recording status of event {} removed from scheduling service.", eventId);
847 return;
848 }
849 } catch (NotFoundException e) {
850 throw e;
851 } catch (Exception e) {
852 throw new SchedulerException(
853 "Unable to remove recording status of event " + eventId + " from the scheduler service", e);
854 } finally {
855 closeConnection(response);
856 }
857 throw new SchedulerException("Unable to remove recording status of event " + eventId);
858 }
859
860 @Override
861 public Map<String, Recording> getKnownRecordings() throws SchedulerException {
862 HttpGet get = new HttpGet("recordingStatus");
863 HttpResponse response = getResponse(get, SC_OK);
864 try {
865 if (response != null) {
866 if (SC_OK == response.getStatusLine().getStatusCode()) {
867 String recordingStates = EntityUtils.toString(response.getEntity(), UTF_8);
868 JSONArray recordings = (JSONArray) parser.parse(recordingStates);
869 Map<String, Recording> recordingsMap = new HashMap<String, Recording>();
870 for (int i = 0; i < recordings.size(); i++) {
871 JSONObject recording = (JSONObject) recordings.get(i);
872 String recordingId = (String) recording.get("id");
873 String status = (String) recording.get("state");
874 Long lastHeard = (Long) recording.get("lastHeardFrom");
875 recordingsMap.put(recordingId, new RecordingImpl(recordingId, status, lastHeard));
876 }
877 logger.info("Successfully get recording states from the remote scheduler service");
878 return recordingsMap;
879 }
880 }
881 } catch (Exception e) {
882 throw new SchedulerException("Unable to get recording states from remote scheduler service", e);
883 } finally {
884 closeConnection(response);
885 }
886 throw new SchedulerException("Unable to get recording states from remote scheduler service");
887 }
888
889 private String toPropertyString(Map<String, String> properties) {
890 StringBuilder wfPropertiesString = new StringBuilder();
891 for (Map.Entry<String, String> entry : properties.entrySet())
892 wfPropertiesString.append(entry.getKey() + "=" + entry.getValue() + "\n");
893 return wfPropertiesString.toString();
894 }
895
896 @Reference
897 @Override
898 public void setTrustedHttpClient(TrustedHttpClient trustedHttpClient) {
899 super.setTrustedHttpClient(trustedHttpClient);
900 }
901 @Reference
902 @Override
903 public void setRemoteServiceManager(ServiceRegistry serviceRegistry) {
904 super.setRemoteServiceManager(serviceRegistry);
905 }
906
907 }