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.workflow.handler.assetmanager;
23
24 import org.opencastproject.assetmanager.api.AssetManager;
25 import org.opencastproject.assetmanager.api.Snapshot;
26 import org.opencastproject.job.api.JobContext;
27 import org.opencastproject.mediapackage.MediaPackage;
28 import org.opencastproject.mediapackage.MediaPackageElement;
29 import org.opencastproject.mediapackage.MediaPackageElementFlavor;
30 import org.opencastproject.mediapackage.selector.SimpleElementSelector;
31 import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
32 import org.opencastproject.workflow.api.WorkflowInstance;
33 import org.opencastproject.workflow.api.WorkflowOperationException;
34 import org.opencastproject.workflow.api.WorkflowOperationHandler;
35 import org.opencastproject.workflow.api.WorkflowOperationInstance;
36 import org.opencastproject.workflow.api.WorkflowOperationResult;
37
38 import org.apache.commons.lang3.StringUtils;
39 import org.osgi.service.component.annotations.Component;
40 import org.osgi.service.component.annotations.Reference;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collection;
47 import java.util.List;
48
49
50
51
52
53
54
55
56
57 @Component(immediate = true, service = WorkflowOperationHandler.class, property = {
58 "service.description=Selects a mp version from the archive", "workflow.operation=select-version" })
59 public class SelectVersionWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
60
61 private static final Logger logger = LoggerFactory.getLogger(SelectVersionWorkflowOperationHandler.class);
62
63 public static final String OPT_VERSION = "version";
64 public static final String OPT_NO_TAGS = "no-tags";
65 public static final String OPT_SOURCE_FLAVORS = "source-flavors";
66
67 private AssetManager assetManager;
68
69 @Override
70 public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
71 throws WorkflowOperationException {
72
73 final WorkflowOperationInstance currentOperation = workflowInstance.getCurrentOperation();
74 if (currentOperation == null) {
75 throw new WorkflowOperationException("Cannot get current workflow operation");
76 }
77
78 MediaPackage mp = workflowInstance.getMediaPackage();
79 MediaPackage resultMp = null;
80
81
82 String version = StringUtils.trimToNull(currentOperation.getConfiguration(OPT_VERSION));
83 String noTagsOpt = StringUtils.trimToNull(currentOperation.getConfiguration(OPT_NO_TAGS));
84 String sourceFlavorsOpt = StringUtils.trimToNull(currentOperation.getConfiguration(OPT_SOURCE_FLAVORS));
85 if (version != null && (noTagsOpt != null || sourceFlavorsOpt != null)) {
86 throw new WorkflowOperationException(
87 String.format("Configuration error: '%s' cannot be used with '%s' and '%s'.",
88 OPT_VERSION, OPT_NO_TAGS, OPT_SOURCE_FLAVORS));
89 }
90
91
92 if (version != null) {
93 try {
94
95 Integer.parseInt(version);
96 resultMp = findVersion(mp.getIdentifier().toString(), version);
97 if (resultMp == null) {
98 throw new WorkflowOperationException(
99 String.format("Could not find version %d of mp %s in the archive", mp.getIdentifier(), version));
100 }
101 } catch (NumberFormatException e) {
102 throw new WorkflowOperationException("Invalid version passed: " + version);
103 }
104 } else {
105 if (noTagsOpt == null || sourceFlavorsOpt == null) {
106 throw new WorkflowOperationException(String.format("Configuration error: both '%s' and '%s' must be passed.",
107 OPT_NO_TAGS, OPT_SOURCE_FLAVORS));
108 }
109 Collection<String> noTags = Arrays.asList(noTagsOpt.split(","));
110
111 SimpleElementSelector elementSelector = new SimpleElementSelector();
112 for (MediaPackageElementFlavor flavor : parseFlavors(sourceFlavorsOpt)) {
113 elementSelector.addFlavor(flavor);
114 }
115
116 resultMp = findVersionWithNoTags(mp.getIdentifier().toString(), elementSelector, noTags);
117 if (resultMp == null) {
118 throw new WorkflowOperationException(String.format(
119 "Could not find in the archive a version of mp %s that does not have the tags %s in element flavors %s",
120 mp.getIdentifier(), noTagsOpt, sourceFlavorsOpt));
121 }
122 }
123 return createResult(resultMp, WorkflowOperationResult.Action.CONTINUE);
124 }
125
126 private MediaPackage findVersion(String mpId, String version) throws WorkflowOperationException {
127
128 List<Snapshot> snapshots = assetManager.getSnapshotsByIdAndVersion(mpId, assetManager.toVersion(version).get());
129
130 if (snapshots.size() > 1) {
131
132 throw new WorkflowOperationException(
133 String.format("Multiple media package %s, version %s found in the archive.", mpId, version));
134 }
135 if (snapshots.isEmpty()) {
136
137 throw new WorkflowOperationException(
138 String.format("Media package %s, version %s not found in the archive.", mpId, version));
139 }
140
141 logger.info("Replacing current media package with version: {}", version);
142 return snapshots.get(0).getMediaPackage();
143 }
144
145 private MediaPackage findVersionWithNoTags(String mpId, SimpleElementSelector elementSelector,
146 Collection<String> tags) throws WorkflowOperationException {
147
148 List<Snapshot> snapshots = assetManager.getSnapshotsByIdOrderedByVersion(mpId, false);
149
150 if (snapshots.isEmpty()) {
151
152 throw new WorkflowOperationException("Media package not found in the archive: " + mpId);
153 }
154
155 nextVersion: for (Snapshot snapshot : snapshots) {
156 MediaPackage mp = snapshot.getMediaPackage();
157 for (MediaPackageElement el : elementSelector.select(mp, false)) {
158 for (String t : el.getTags()) {
159 if (tags.contains(t)) {
160 continue nextVersion;
161 }
162 }
163 }
164 logger.info("Replacing current media package with version: {}", snapshot.getVersion());
165 return mp;
166 }
167 return null;
168 }
169
170 private List<MediaPackageElementFlavor> parseFlavors(String flavorStr) {
171 List<MediaPackageElementFlavor> flavors = new ArrayList<MediaPackageElementFlavor>();
172 if (flavorStr != null) {
173 for (String flavor : asList(flavorStr)) {
174 flavors.add(MediaPackageElementFlavor.parseFlavor(flavor));
175 }
176 }
177 return flavors;
178 }
179
180 @Reference
181 public void setAssetManager(AssetManager service) {
182 this.assetManager = service;
183 }
184 }