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.execute.operation.handler;
23
24 import org.opencastproject.execute.api.ExecuteException;
25 import org.opencastproject.execute.api.ExecuteService;
26 import org.opencastproject.inspection.api.MediaInspectionException;
27 import org.opencastproject.inspection.api.MediaInspectionService;
28 import org.opencastproject.job.api.Job;
29 import org.opencastproject.job.api.JobContext;
30 import org.opencastproject.mediapackage.MediaPackage;
31 import org.opencastproject.mediapackage.MediaPackageElement;
32 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
33 import org.opencastproject.mediapackage.MediaPackageElementParser;
34 import org.opencastproject.mediapackage.MediaPackageException;
35 import org.opencastproject.serviceregistry.api.ServiceRegistry;
36 import org.opencastproject.util.NotFoundException;
37 import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
38 import org.opencastproject.workflow.api.ConfiguredTagsAndFlavors;
39 import org.opencastproject.workflow.api.WorkflowInstance;
40 import org.opencastproject.workflow.api.WorkflowOperationException;
41 import org.opencastproject.workflow.api.WorkflowOperationHandler;
42 import org.opencastproject.workflow.api.WorkflowOperationInstance;
43 import org.opencastproject.workflow.api.WorkflowOperationResult;
44 import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
45 import org.opencastproject.workflow.api.WorkflowOperationResultImpl;
46 import org.opencastproject.workspace.api.Workspace;
47
48 import org.apache.commons.lang3.StringUtils;
49 import org.osgi.service.component.annotations.Component;
50 import org.osgi.service.component.annotations.Reference;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import java.io.File;
55 import java.io.FileInputStream;
56 import java.io.IOException;
57 import java.io.InputStreamReader;
58 import java.net.URI;
59 import java.nio.charset.StandardCharsets;
60 import java.util.HashMap;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.Properties;
64
65
66
67
68 @Component(
69 immediate = true,
70 service = WorkflowOperationHandler.class,
71 property = {
72 "service.description=Execute Once Workflow Operation Handler",
73 "workflow.operation=execute-once"
74 }
75 )
76 public class ExecuteOnceWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
77
78
79 private static final Logger logger = LoggerFactory.getLogger(ExecuteOnceWorkflowOperationHandler.class);
80
81
82 public static final String EXEC_PROPERTY = "exec";
83
84
85 public static final String PARAMS_PROPERTY = "params";
86
87
88 public static final String LOAD_PROPERTY = "load";
89
90
91 public static final String OUTPUT_FILENAME_PROPERTY = "output-filename";
92
93
94 public static final String EXPECTED_TYPE_PROPERTY = "expected-type";
95
96
97 public static final String TARGET_FLAVOR_PROPERTY = "target-flavor";
98
99
100 public static final String TARGET_FLAVORS_PROPERTY = "target-flavors";
101
102
103 public static final String TARGET_TAGS_PROPERTY = "target-tags";
104
105
106 public static final String TARGET_TAG_PROPERTY = "target-tag";
107
108
109 public static final String SET_WF_PROPS_PROPERTY = "set-workflow-properties";
110
111
112 protected ExecuteService executeService;
113
114
115 private MediaInspectionService inspectionService = null;
116
117
118 protected Workspace workspace;
119
120
121
122
123
124
125
126 @Override
127 public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context)
128 throws WorkflowOperationException {
129
130 MediaPackage mediaPackage = workflowInstance.getMediaPackage();
131 WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
132
133 logger.debug("Running execute workflow operation with ID {}", operation.getId());
134
135
136 String exec = StringUtils.trimToNull(operation.getConfiguration(EXEC_PROPERTY));
137 String params = StringUtils.trimToNull(operation.getConfiguration(PARAMS_PROPERTY));
138 float load = 1.0f;
139 String loadPropertyStr = StringUtils.trimToEmpty(operation.getConfiguration(LOAD_PROPERTY));
140 if (StringUtils.isNotBlank(loadPropertyStr)) {
141 try {
142 load = Float.parseFloat(loadPropertyStr);
143 } catch (NumberFormatException e) {
144 String description = StringUtils.trimToEmpty(operation.getDescription());
145 logger.warn("Ignoring invalid load value '{}' on execute operation with description '{}'",
146 loadPropertyStr, description);
147 }
148 }
149 ConfiguredTagsAndFlavors tagsAndFlavors = getTagsAndFlavors(workflowInstance,
150 Configuration.none, Configuration.none, Configuration.many, Configuration.many);
151 List<MediaPackageElementFlavor> targetFlavorStr = tagsAndFlavors.getTargetFlavors();
152 ConfiguredTagsAndFlavors.TargetTags targetTags = tagsAndFlavors.getTargetTags();
153 String outputFilename = StringUtils.trimToNull(operation.getConfiguration(OUTPUT_FILENAME_PROPERTY));
154 String expectedTypeStr = StringUtils.trimToNull(operation.getConfiguration(EXPECTED_TYPE_PROPERTY));
155
156 boolean setWfProps = Boolean.valueOf(StringUtils.trimToNull(operation.getConfiguration(SET_WF_PROPS_PROPERTY)));
157
158
159 MediaPackageElementFlavor targetFlavor = null;
160 if (!targetFlavorStr.isEmpty()) {
161 targetFlavor = targetFlavorStr.get(0);
162 }
163
164
165 MediaPackageElement.Type expectedType = null;
166 if (expectedTypeStr != null) {
167 for (MediaPackageElement.Type type : MediaPackageElement.Type.values()) {
168 if (type.toString().equalsIgnoreCase(expectedTypeStr)) {
169 expectedType = type;
170 break;
171 }
172 }
173 if (expectedType == null) {
174 throw new WorkflowOperationException("'" + expectedTypeStr + "' is not a valid element type");
175 }
176 }
177
178
179 MediaPackageElement resultElement = null;
180
181 try {
182 Job job = executeService.execute(exec, params, mediaPackage, outputFilename, expectedType, load);
183
184 WorkflowOperationResult result = null;
185
186
187 if (!waitForStatus(job).isSuccess()) {
188 throw new WorkflowOperationException("Execute operation failed");
189 }
190
191 if (StringUtils.isNotBlank(job.getPayload())) {
192
193 if (setWfProps) {
194
195 resultElement = MediaPackageElementParser.getFromXml(job.getPayload());
196
197 final Properties properties = new Properties();
198 File propertiesFile = workspace.get(resultElement.getURI());
199 try (InputStreamReader reader = new InputStreamReader(
200 new FileInputStream(propertiesFile),
201 StandardCharsets.UTF_8
202 )) {
203 properties.load(reader);
204 }
205 logger.debug("Loaded {} properties from {}", properties.size(), propertiesFile);
206 workspace.deleteFromCollection(ExecuteService.COLLECTION, propertiesFile.getName());
207
208 Map<String, String> wfProps = new HashMap<String, String>((Map) properties);
209
210 result = createResult(mediaPackage, wfProps, Action.CONTINUE, job.getQueueTime());
211 } else {
212
213 resultElement = MediaPackageElementParser.getFromXml(job.getPayload());
214
215 if (resultElement.getElementType() == MediaPackageElement.Type.Track) {
216
217 Job inspectionJob = null;
218 inspectionJob = inspectionService.inspect(resultElement.getURI());
219
220 if (!waitForStatus(inspectionJob).isSuccess()) {
221 throw new ExecuteException("Media inspection of " + resultElement.getURI() + " failed");
222 }
223
224 resultElement = MediaPackageElementParser.getFromXml(inspectionJob.getPayload());
225 }
226
227
228 mediaPackage.add(resultElement);
229 URI uri = workspace.moveTo(resultElement.getURI(), mediaPackage.getIdentifier().toString(),
230 resultElement.getIdentifier(), outputFilename);
231 resultElement.setURI(uri);
232
233
234 if (targetFlavor != null) {
235 resultElement.setFlavor(targetFlavor);
236 }
237
238
239 applyTargetTagsToElement(targetTags, resultElement);
240
241 result = createResult(mediaPackage, Action.CONTINUE, job.getQueueTime());
242 }
243 } else {
244
245 result = createResult(mediaPackage, Action.CONTINUE, job.getQueueTime());
246 }
247
248 logger.debug("Execute operation {} completed", operation.getId());
249
250 return result;
251
252 } catch (ExecuteException e) {
253 throw new WorkflowOperationException(e);
254 } catch (MediaPackageException e) {
255 throw new WorkflowOperationException("Some result element couldn't be serialized", e);
256 } catch (NotFoundException e) {
257 throw new WorkflowOperationException("Could not find mediapackage", e);
258 } catch (IOException e) {
259 throw new WorkflowOperationException("Error unmarshalling a result mediapackage element", e);
260 } catch (MediaInspectionException e) {
261 throw new WorkflowOperationException("Media inspection of " + resultElement.getURI() + " failed", e);
262 }
263
264 }
265
266
267
268
269
270
271
272 @Override
273 public WorkflowOperationResult skip(WorkflowInstance workflowInstance, JobContext context)
274 throws WorkflowOperationException {
275 return new WorkflowOperationResultImpl(workflowInstance.getMediaPackage(), null, Action.SKIP, 0);
276 }
277
278 @Override
279 public String getId() {
280 return "execute";
281 }
282
283 @Override
284 public String getDescription() {
285 return "Executes command line workflow operations in workers";
286 }
287
288 @Override
289 public void destroy(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
290
291 }
292
293
294
295
296
297
298 @Reference
299 public void setExecuteService(ExecuteService service) {
300 this.executeService = service;
301 }
302
303
304
305
306
307
308 @Reference
309 public void setWorkspace(Workspace workspace) {
310 this.workspace = workspace;
311 }
312
313
314
315
316
317
318
319 @Reference
320 protected void setMediaInspectionService(MediaInspectionService mediaInspectionService) {
321 this.inspectionService = mediaInspectionService;
322 }
323
324 @Reference
325 @Override
326 public void setServiceRegistry(ServiceRegistry serviceRegistry) {
327 super.setServiceRegistry(serviceRegistry);
328 }
329 }