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