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.impl;
23
24 import org.opencastproject.mediapackage.MediaPackage;
25 import org.opencastproject.metadata.dublincore.DublinCore;
26 import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
27 import org.opencastproject.security.api.UnauthorizedException;
28 import org.opencastproject.series.api.SeriesException;
29 import org.opencastproject.series.api.SeriesService;
30 import org.opencastproject.util.NotFoundException;
31
32 import net.fortuna.ical4j.model.Calendar;
33 import net.fortuna.ical4j.model.DateTime;
34 import net.fortuna.ical4j.model.ParameterList;
35 import net.fortuna.ical4j.model.component.VEvent;
36 import net.fortuna.ical4j.model.parameter.Encoding;
37 import net.fortuna.ical4j.model.parameter.FmtType;
38 import net.fortuna.ical4j.model.parameter.Value;
39 import net.fortuna.ical4j.model.parameter.XParameter;
40 import net.fortuna.ical4j.model.property.Attach;
41 import net.fortuna.ical4j.model.property.CalScale;
42 import net.fortuna.ical4j.model.property.Description;
43 import net.fortuna.ical4j.model.property.LastModified;
44 import net.fortuna.ical4j.model.property.Location;
45 import net.fortuna.ical4j.model.property.ProdId;
46 import net.fortuna.ical4j.model.property.RelatedTo;
47 import net.fortuna.ical4j.model.property.Uid;
48 import net.fortuna.ical4j.model.property.Version;
49
50 import org.apache.commons.lang3.StringUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import java.io.IOException;
55 import java.util.Date;
56 import java.util.HashMap;
57 import java.util.Map;
58
59
60
61
62 public class CalendarGenerator {
63
64
65 private static final Logger logger = LoggerFactory.getLogger(CalendarGenerator.class);
66
67
68 protected Calendar cal;
69
70
71 protected SeriesService seriesService;
72
73 private final Map<String, DublinCoreCatalog> series = new HashMap<>();
74
75
76
77
78
79
80
81 public CalendarGenerator(SeriesService seriesService) {
82 cal = new Calendar();
83 cal.getProperties().add(new ProdId("Opencast Calendar File 0.5"));
84 cal.getProperties().add(Version.VERSION_2_0);
85 cal.getProperties().add(CalScale.GREGORIAN);
86 this.seriesService = seriesService;
87 }
88
89
90
91
92
93
94 public Calendar getCalendar() {
95 return cal;
96 }
97
98
99
100
101
102
103
104 public void setCalendar(Calendar cal) {
105 this.cal = cal;
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public boolean addEvent(MediaPackage mp, DublinCoreCatalog catalog, String agentId, Date start, Date end,
125 Date lastModified, String captureAgentMetadata) {
126 String eventId = mp.getIdentifier().toString();
127
128 logger.debug("Creating iCalendar VEvent from scheduled event '{}'", eventId);
129
130 DateTime startDate = new DateTime(start);
131 DateTime endDate = new DateTime(end);
132 Date marginEndDate = new org.joda.time.DateTime(endDate.getTime()).plusHours(1).toDate();
133 if (marginEndDate.before(new Date())) {
134 logger.debug("Event has already passed more than an hour, skipping!");
135 return false;
136 }
137 startDate.setUtc(true);
138 endDate.setUtc(true);
139 String seriesID = null;
140
141 VEvent event = new VEvent(startDate, endDate, catalog.getFirst(DublinCore.PROPERTY_TITLE));
142 try {
143 event.getProperties().add(new Uid(eventId));
144
145 DateTime lastModifiedDate = new DateTime(lastModified);
146 lastModifiedDate.setUtc(true);
147 event.getProperties().add(new LastModified(lastModifiedDate));
148
149 if (StringUtils.isNotEmpty(catalog.getFirst(DublinCore.PROPERTY_DESCRIPTION))) {
150 event.getProperties().add(new Description(catalog.getFirst(DublinCore.PROPERTY_DESCRIPTION)));
151 }
152 event.getProperties().add(new Location(agentId));
153 if (StringUtils.isNotEmpty(catalog.getFirst(DublinCore.PROPERTY_IS_PART_OF))) {
154 seriesID = catalog.getFirst(DublinCore.PROPERTY_IS_PART_OF);
155 event.getProperties().add(new RelatedTo(seriesID));
156 }
157
158 ParameterList dcParameters = new ParameterList();
159 dcParameters.add(new FmtType("application/xml"));
160 dcParameters.add(Value.BINARY);
161 dcParameters.add(Encoding.BASE64);
162 dcParameters.add(new XParameter("X-APPLE-FILENAME", "episode.xml"));
163 Attach metadataAttachment = new Attach(dcParameters, catalog.toXmlString().getBytes("UTF-8"));
164 event.getProperties().add(metadataAttachment);
165
166 String seriesDC = getSeriesDublinCoreAsString(seriesID);
167 if (seriesDC != null) {
168 logger.debug("Attaching series {} information to event {}", seriesID, eventId);
169 ParameterList sDcParameters = new ParameterList();
170 sDcParameters.add(new FmtType("application/xml"));
171 sDcParameters.add(Value.BINARY);
172 sDcParameters.add(Encoding.BASE64);
173 sDcParameters.add(new XParameter("X-APPLE-FILENAME", "series.xml"));
174 Attach seriesAttachment = new Attach(sDcParameters, seriesDC.getBytes("UTF-8"));
175 event.getProperties().add(seriesAttachment);
176 } else {
177 logger.debug("No series provided for event {}.", eventId);
178 }
179
180 ParameterList caParameters = new ParameterList();
181 caParameters.add(new FmtType("application/text"));
182 caParameters.add(Value.BINARY);
183 caParameters.add(Encoding.BASE64);
184 caParameters.add(new XParameter("X-APPLE-FILENAME", "org.opencastproject.capture.agent.properties"));
185 Attach agentsAttachment = new Attach(caParameters, captureAgentMetadata.getBytes("UTF-8"));
186 event.getProperties().add(agentsAttachment);
187
188 } catch (Exception e) {
189 logger.error("Unable to add event '{}' to recording calendar", eventId, e);
190 return false;
191 }
192
193 cal.getComponents().add(event);
194
195 logger.debug("new VEvent = {} ", event.toString());
196 return true;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211 private String getSeriesDublinCoreAsString(String seriesID) throws UnauthorizedException, NotFoundException {
212 if (StringUtils.isBlank(seriesID))
213 return null;
214 if (seriesService == null) {
215 logger.warn("No SeriesService available");
216 return null;
217 }
218
219 DublinCoreCatalog seriesDC = series.get(seriesID);
220 if (seriesDC == null) {
221 try {
222 seriesDC = seriesService.getSeries(seriesID);
223 series.put(seriesID, seriesDC);
224 } catch (SeriesException e) {
225 logger.error("Error loading DublinCoreCatalog for series '{}'", seriesID, e);
226 return null;
227 }
228 }
229
230 try {
231 return seriesDC.toXmlString();
232 } catch (IOException e) {
233 logger.error("Error serializing DublinCoreCatalog of series '{}'", seriesID, e);
234 return null;
235 }
236 }
237
238 }