AssetManagerSnapshotWorkflowOperationHandler.java
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.workflow.handler.assetmanager;
import static org.opencastproject.assetmanager.api.AssetManager.DEFAULT_OWNER;
import org.opencastproject.assetmanager.api.AssetManager;
import org.opencastproject.job.api.JobContext;
import org.opencastproject.mediapackage.MediaPackage;
import org.opencastproject.mediapackage.MediaPackageElement;
import org.opencastproject.mediapackage.MediaPackageElementFlavor;
import org.opencastproject.mediapackage.MediaPackageException;
import org.opencastproject.mediapackage.MediaPackageReference;
import org.opencastproject.mediapackage.Publication;
import org.opencastproject.mediapackage.selector.SimpleElementSelector;
import org.opencastproject.serviceregistry.api.ServiceRegistry;
import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
import org.opencastproject.workflow.api.ConfiguredTagsAndFlavors;
import org.opencastproject.workflow.api.WorkflowInstance;
import org.opencastproject.workflow.api.WorkflowOperationException;
import org.opencastproject.workflow.api.WorkflowOperationHandler;
import org.opencastproject.workflow.api.WorkflowOperationInstance;
import org.opencastproject.workflow.api.WorkflowOperationResult;
import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Workflow operation for taking a snapshot of a media package.
*
* @see AssetManager#takeSnapshot(String, MediaPackage)
*/
@Component(
immediate = true,
name = "org.opencastproject.workflow.handler.assetmanager.AssetManagerAddWorkflowOperationHandler",
service = WorkflowOperationHandler.class,
property = {
"service.description=Asset Manager Take Snapshot Workflow Operation Handler",
"workflow.operation=snapshot"
}
)
public class AssetManagerSnapshotWorkflowOperationHandler extends AbstractWorkflowOperationHandler {
private static final Logger logger = LoggerFactory.getLogger(AssetManagerSnapshotWorkflowOperationHandler.class);
/** The asset manager. */
private AssetManager assetManager;
@Activate
@Override
public void activate(ComponentContext cc) {
super.activate(cc);
}
/** OSGi DI */
@Reference
public void setAssetManager(AssetManager assetManager) {
this.assetManager = assetManager;
}
@Override
public WorkflowOperationResult start(WorkflowInstance wi, JobContext ctx)
throws WorkflowOperationException {
final MediaPackage mpWorkflow = wi.getMediaPackage();
final WorkflowOperationInstance currentOperation = wi.getCurrentOperation();
// Check which tags have been configured
ConfiguredTagsAndFlavors tagsAndFlavors = getTagsAndFlavors(wi,
Configuration.many, Configuration.many, Configuration.none, Configuration.none);
List<String> sourceTagsOption = tagsAndFlavors.getSrcTags();
List<MediaPackageElementFlavor> sourceFlavorsOption = tagsAndFlavors.getSrcFlavors();
if (sourceTagsOption.isEmpty() && sourceFlavorsOption.isEmpty()) {
logger.debug("No source tags have been specified, so everything will be added to the AssetManager");
}
final List<String> tagSet;
// If a set of tags has been specified, use it
if (!sourceTagsOption.isEmpty()) {
tagSet = sourceTagsOption;
} else {
tagSet = new ArrayList<>();
}
try {
final MediaPackage mpAssetManager = getMediaPackageForArchival(mpWorkflow, tagSet, sourceFlavorsOption);
if (mpAssetManager != null) {
logger.info("Take snapshot of media package {}", mpAssetManager);
// adding media package to the episode service
assetManager.takeSnapshot(DEFAULT_OWNER, mpAssetManager);
logger.debug("Snapshot operation complete");
return createResult(mpWorkflow, Action.CONTINUE);
} else {
return createResult(mpWorkflow, Action.CONTINUE);
}
} catch (Throwable t) {
throw new WorkflowOperationException(t);
}
}
protected MediaPackage getMediaPackageForArchival(MediaPackage current, List<String> tags,
List<MediaPackageElementFlavor> sourceFlavors)
throws MediaPackageException {
MediaPackage mp = (MediaPackage) current.clone();
Collection<MediaPackageElement> keep;
if (tags.isEmpty() && sourceFlavors.isEmpty()) {
keep = new ArrayList<>(Arrays.asList(current.getElementsByTags(tags)));
} else {
SimpleElementSelector simpleElementSelector = new SimpleElementSelector();
for (MediaPackageElementFlavor flavor : sourceFlavors) {
simpleElementSelector.addFlavor(flavor);
}
for (String tag : tags) {
simpleElementSelector.addTag(tag);
}
keep = simpleElementSelector.select(current, false);
}
// Also archive the publication elements
for (Publication publication : current.getPublications()) {
keep.add(publication);
}
// Mark everything that is set for removal
List<MediaPackageElement> removals = new ArrayList<MediaPackageElement>();
for (MediaPackageElement element : mp.getElements()) {
if (!keep.contains(element)) {
removals.add(element);
}
}
// Fix references and flavors
for (MediaPackageElement element : mp.getElements()) {
if (removals.contains(element)) {
continue;
}
// Is the element referencing anything?
MediaPackageReference reference = element.getReference();
if (reference != null) {
MediaPackageElement referencedElement = mp.getElementByReference(reference);
// if we are distributing the referenced element, everything is fine. Otherwise...
if (referencedElement != null && removals.contains(referencedElement)) {
// Follow the references until we find a flavor
MediaPackageElement parent;
while ((parent = current.getElementByReference(reference)) != null) {
if (parent.getFlavor() != null && element.getFlavor() == null) {
element.setFlavor(parent.getFlavor());
}
if (parent.getReference() == null) {
break;
}
reference = parent.getReference();
}
// Done. Let's cut the path but keep references to the mediapackage itself
if (reference != null && reference.getType().equals(MediaPackageReference.TYPE_MEDIAPACKAGE)) {
element.setReference(reference);
} else {
element.clearReference();
}
}
}
}
// Remove everything we don't want to add to publish
for (MediaPackageElement element : removals) {
mp.remove(element);
}
return mp;
}
@Reference
@Override
public void setServiceRegistry(ServiceRegistry serviceRegistry) {
super.setServiceRegistry(serviceRegistry);
}
}