use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class DownloadDistributionServiceImpl method distributeElement.
/**
* Distribute a Mediapackage element to the download distribution service.
*
* @param channelId
* # The id of the publication channel to be distributed to.
* @param mediapackage
* The media package that contains the element to be distributed.
* @param element
* The the element that should be distributed contained within the media package.
* @param checkAvailability
* Check the availability of the distributed element via http.
* @param preserveReference
* Copy existing Track-Reference to the new distributed Track
* @return A reference to the MediaPackageElement that has been distributed.
* @throws DistributionException
* Thrown if the parent directory of the MediaPackageElement cannot be created, if the MediaPackageElement
* cannot be copied or another unexpected exception occurs.
*/
public MediaPackageElement distributeElement(String channelId, MediaPackage mediapackage, MediaPackageElement element, boolean checkAvailability, boolean preserveReference) throws DistributionException {
final String mediapackageId = mediapackage.getIdentifier().compact();
final String elementId = element.getIdentifier();
try {
File source;
try {
source = workspace.get(element.getURI());
} catch (NotFoundException e) {
throw new DistributionException("Unable to find " + element.getURI() + " in the workspace", e);
} catch (IOException e) {
throw new DistributionException("Error loading " + element.getURI() + " from the workspace", e);
}
// Try to find a duplicated element source
try {
source = findDuplicatedElementSource(source, mediapackageId);
} catch (IOException e) {
logger.warn("Unable to find duplicated source {}: {}", source, ExceptionUtils.getMessage(e));
}
File destination = getDistributionFile(channelId, mediapackage, element);
if (!destination.equals(source)) {
// Put the file in place if sourcesfile differs destinationfile
try {
FileUtils.forceMkdir(destination.getParentFile());
} catch (IOException e) {
throw new DistributionException("Unable to create " + destination.getParentFile(), e);
}
logger.debug("Distributing element {} of media package {} to publication channel {} ({})", elementId, mediapackageId, channelId, destination);
try {
FileSupport.link(source, destination, true);
} catch (IOException e) {
throw new DistributionException(format("Unable to copy %s to %s", source, destination), e);
}
}
// Create a media package element representation of the distributed file
MediaPackageElement distributedElement = (MediaPackageElement) element.clone();
try {
distributedElement.setURI(getDistributionUri(channelId, mediapackageId, element));
if (preserveReference) {
distributedElement.setReference(element.getReference());
}
} catch (URISyntaxException e) {
throw new DistributionException("Distributed element produces an invalid URI", e);
}
logger.debug("Finished distributing element {} of media package {} to publication channel {}", elementId, mediapackageId, channelId);
final URI uri = distributedElement.getURI();
if (checkAvailability) {
logger.debug("Checking availability of distributed artifact {} at {}", distributedElement, uri);
waitForResource(trustedHttpClient, uri, HttpServletResponse.SC_OK, TIMEOUT, INTERVAL).fold(Misc.<Exception, Void>chuck(), new Effect.X<Integer>() {
@Override
public void xrun(Integer status) throws Exception {
if (ne(status, HttpServletResponse.SC_OK)) {
logger.warn("Attempt to access distributed file {} returned code {}", uri, status);
throw new DistributionException("Unable to load distributed file " + uri.toString());
}
}
});
}
return distributedElement;
} catch (Exception e) {
logger.warn("Error distributing " + element, e);
if (e instanceof DistributionException) {
throw (DistributionException) e;
} else {
throw new DistributionException(e);
}
}
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class StreamingDistributionServiceImpl method process.
/**
* {@inheritDoc}
*
* @see org.opencastproject.job.api.AbstractJobProducer#process(org.opencastproject.job.api.Job)
*/
@Override
protected String process(Job job) throws Exception {
Operation op = null;
String operation = job.getOperation();
List<String> arguments = job.getArguments();
try {
op = Operation.valueOf(operation);
String channelId = arguments.get(0);
MediaPackage mediapackage = MediaPackageParser.getFromXml(arguments.get(1));
Set<String> elementIds = gson.fromJson(arguments.get(2), new TypeToken<Set<String>>() {
}.getType());
switch(op) {
case Distribute:
MediaPackageElement[] distributedElements = distributeElements(channelId, mediapackage, elementIds);
return (distributedElements != null) ? MediaPackageElementParser.getArrayAsXml(Arrays.asList(distributedElements)) : null;
case Retract:
MediaPackageElement[] retractedElements = retractElements(channelId, mediapackage, elementIds);
return (retractedElements != null) ? MediaPackageElementParser.getArrayAsXml(Arrays.asList(retractedElements)) : null;
default:
throw new IllegalStateException("Don't know how to handle operation '" + operation + "'");
}
} catch (IllegalArgumentException e) {
throw new ServiceRegistryException("This service can't handle operations of type '" + op + "'", e);
} catch (IndexOutOfBoundsException e) {
throw new ServiceRegistryException("This argument list for operation '" + op + "' does not meet expectations", e);
} catch (Exception e) {
throw new ServiceRegistryException("Error handling operation '" + op + "'", e);
}
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class StreamingDistributionServiceImpl method retractElement.
/**
* Retracts the mediapackage with the given identifier from the distribution channel.
*
* @param channelId
* the channel id
* @param mp
* the mediapackage
* @param mpeId
* the element identifier
* @return the retracted element or <code>null</code> if the element was not retracted
*/
private MediaPackageElement retractElement(final String channelId, final MediaPackage mp, final String mpeId) throws DistributionException {
RequireUtil.notNull(channelId, "channelId");
RequireUtil.notNull(mp, "mp");
RequireUtil.notNull(mpeId, "elementId");
// Make sure the element exists
final MediaPackageElement mpe = mp.getElementById(mpeId);
if (mpe == null) {
throw new IllegalStateException("No element " + mpeId + " found in media package");
}
try {
for (final File mpeFile : locations.get().getDistributionFileFrom(mpe.getURI())) {
logger.info("Retracting element {} from {}", mpe, mpeFile);
// or has been removed otherwise
if (mpeFile.exists()) {
// Try to remove the file and - if possible - the parent folder
final File parentDir = mpeFile.getParentFile();
FileUtils.forceDelete(mpeFile);
FileSupport.deleteHierarchyIfEmpty(new File(locations.get().getBaseDir()), parentDir);
logger.info("Finished retracting element {} of media package {}", mpeId, mp);
return mpe;
} else {
logger.info(format("Element %s@%s has already been removed from publication channel %s", mpeId, mp.getIdentifier(), channelId));
return mpe;
}
}
// could not extract a file from the element's URI
logger.info(format("Element %s has not been published to publication channel %s", mpe.getURI(), channelId));
return mpe;
} catch (Exception e) {
logger.warn(format("Error retracting element %s of media package %s", mpeId, mp), e);
if (e instanceof DistributionException) {
throw (DistributionException) e;
} else {
throw new DistributionException(e);
}
}
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class ConfigurablePublishWorkflowOperationHandler method start.
@Override
public WorkflowOperationResult start(WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
RequireUtil.notNull(workflowInstance, "workflowInstance");
final MediaPackage mp = workflowInstance.getMediaPackage();
final WorkflowOperationInstance op = workflowInstance.getCurrentOperation();
final String channelId = StringUtils.trimToEmpty(op.getConfiguration(CHANNEL_ID_KEY));
if ("".equals(channelId)) {
throw new WorkflowOperationException("Unable to publish this mediapackage as the configuration key " + CHANNEL_ID_KEY + " is missing. Unable to determine where to publish these elements.");
}
final String urlPattern = StringUtils.trimToEmpty(op.getConfiguration(URL_PATTERN));
MimeType mimetype = null;
String mimetypeString = StringUtils.trimToEmpty(op.getConfiguration(MIME_TYPE));
if (!"".equals(mimetypeString)) {
try {
mimetype = MimeTypes.parseMimeType(mimetypeString);
} catch (IllegalArgumentException e) {
throw new WorkflowOperationException("Unable to parse the provided configuration for " + MIME_TYPE, e);
}
}
final boolean withPublishedElements = BooleanUtils.toBoolean(StringUtils.trimToEmpty(op.getConfiguration(WITH_PUBLISHED_ELEMENTS)));
boolean checkAvailability = BooleanUtils.toBoolean(StringUtils.trimToEmpty(op.getConfiguration(CHECK_AVAILABILITY)));
if (getPublications(mp, channelId).size() > 0) {
final String rePublishStrategy = StringUtils.trimToEmpty(op.getConfiguration(STRATEGY));
switch(rePublishStrategy) {
case ("fail"):
// fail is a dummy function for further distribution strategies
fail(mp);
break;
case ("merge"):
// nothing to do here. other publication strategies can be added to this list later on
break;
default:
retract(mp, channelId);
}
}
String mode = StringUtils.trimToEmpty(op.getConfiguration(MODE));
if ("".equals(mode)) {
mode = DEFAULT_MODE;
} else if (!ArrayUtils.contains(KNOWN_MODES, mode)) {
logger.error("Unknown value for configuration key mode: '{}'", mode);
throw new IllegalArgumentException("Unknown value for configuration key mode");
}
final String[] sourceFlavors = StringUtils.split(StringUtils.trimToEmpty(op.getConfiguration(SOURCE_FLAVORS)), ",");
final String[] sourceTags = StringUtils.split(StringUtils.trimToEmpty(op.getConfiguration(SOURCE_TAGS)), ",");
String publicationUUID = UUID.randomUUID().toString();
Publication publication = PublicationImpl.publication(publicationUUID, channelId, null, null);
// Configure the element selector
final SimpleElementSelector selector = new SimpleElementSelector();
for (String flavor : sourceFlavors) {
selector.addFlavor(MediaPackageElementFlavor.parseFlavor(flavor));
}
for (String tag : sourceTags) {
selector.addTag(tag);
}
if (sourceFlavors.length > 0 || sourceTags.length > 0) {
if (!withPublishedElements) {
Set<MediaPackageElement> elements = distribute(selector.select(mp, false), mp, channelId, mode, checkAvailability);
if (elements.size() > 0) {
for (MediaPackageElement element : elements) {
// Make sure the mediapackage is prompted to create a new identifier for this element
element.setIdentifier(null);
PublicationImpl.addElementToPublication(publication, element);
}
} else {
logger.info("No element found for distribution in media package '{}'", mp);
return createResult(mp, Action.CONTINUE);
}
} else {
List<MediaPackageElement> publishedElements = new ArrayList<>();
for (Publication alreadyPublished : mp.getPublications()) {
publishedElements.addAll(Arrays.asList(alreadyPublished.getAttachments()));
publishedElements.addAll(Arrays.asList(alreadyPublished.getCatalogs()));
publishedElements.addAll(Arrays.asList(alreadyPublished.getTracks()));
}
for (MediaPackageElement element : selector.select(publishedElements, false)) {
PublicationImpl.addElementToPublication(publication, element);
}
}
}
if (!"".equals(urlPattern)) {
publication.setURI(populateUrlWithVariables(urlPattern, mp, publicationUUID));
}
if (mimetype != null) {
publication.setMimeType(mimetype);
}
mp.add(publication);
return createResult(mp, Action.CONTINUE);
}
use of org.opencastproject.mediapackage.MediaPackageElement in project opencast by opencast.
the class ConfigurablePublishWorkflowOperationHandlerTest method testNormal.
@Test
public void testNormal() throws WorkflowOperationException, URISyntaxException, DistributionException, MediaPackageException {
String channelId = "engage-player";
String attachmentId = "attachment-id";
String catalogId = "catalog-id";
String trackId = "track-id";
Attachment attachment = new AttachmentImpl();
attachment.addTag("engage-download");
attachment.setIdentifier(attachmentId);
attachment.setURI(new URI("http://api.com/attachment"));
Catalog catalog = CatalogImpl.newInstance();
catalog.addTag("engage-download");
catalog.setIdentifier(catalogId);
catalog.setURI(new URI("http://api.com/catalog"));
Track track = new TrackImpl();
track.addTag("engage-streaming");
track.setIdentifier(trackId);
track.setURI(new URI("http://api.com/track"));
Publication publicationtest = new PublicationImpl(trackId, channelId, new URI("http://api.com/publication"), MimeType.mimeType(trackId, trackId));
Track unrelatedTrack = new TrackImpl();
unrelatedTrack.addTag("unrelated");
Capture<MediaPackageElement> capturePublication = Capture.newInstance();
MediaPackage mediapackageClone = EasyMock.createNiceMock(MediaPackage.class);
EasyMock.expect(mediapackageClone.getElements()).andStubReturn(new MediaPackageElement[] { attachment, catalog, track, unrelatedTrack });
EasyMock.expect(mediapackageClone.getIdentifier()).andStubReturn(new IdImpl("mp-id-clone"));
EasyMock.expectLastCall();
EasyMock.replay(mediapackageClone);
MediaPackage mediapackage = EasyMock.createNiceMock(MediaPackage.class);
EasyMock.expect(mediapackage.getElements()).andStubReturn(new MediaPackageElement[] { attachment, catalog, track, unrelatedTrack });
EasyMock.expect(mediapackage.clone()).andStubReturn(mediapackageClone);
EasyMock.expect(mediapackage.getIdentifier()).andStubReturn(new IdImpl("mp-id"));
mediapackage.add(EasyMock.capture(capturePublication));
mediapackage.add(publicationtest);
EasyMock.expect(mediapackage.getPublications()).andStubReturn(new Publication[] { publicationtest });
EasyMock.expectLastCall();
EasyMock.replay(mediapackage);
WorkflowOperationInstance op = EasyMock.createNiceMock(WorkflowOperationInstance.class);
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.CHANNEL_ID_KEY)).andStubReturn(channelId);
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.MIME_TYPE)).andStubReturn("text/html");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.URL_PATTERN)).andStubReturn("http://api.opencast.org/api/events/${event_id}");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.SOURCE_TAGS)).andStubReturn("engage-download,engage-streaming");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.CHECK_AVAILABILITY)).andStubReturn("true");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.STRATEGY)).andStubReturn("retract");
EasyMock.expect(op.getConfiguration(ConfigurablePublishWorkflowOperationHandler.MODE)).andStubReturn("single");
EasyMock.replay(op);
WorkflowInstance workflowInstance = EasyMock.createNiceMock(WorkflowInstance.class);
EasyMock.expect(workflowInstance.getMediaPackage()).andStubReturn(mediapackage);
EasyMock.expect(workflowInstance.getCurrentOperation()).andStubReturn(op);
EasyMock.replay(workflowInstance);
JobContext jobContext = EasyMock.createNiceMock(JobContext.class);
EasyMock.replay(jobContext);
Job attachmentJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(attachmentJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(attachment));
EasyMock.replay(attachmentJob);
Job catalogJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(catalogJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(catalog));
EasyMock.replay(catalogJob);
Job trackJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(trackJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(track));
EasyMock.replay(trackJob);
Job retractJob = EasyMock.createNiceMock(Job.class);
EasyMock.expect(retractJob.getPayload()).andReturn(MediaPackageElementParser.getAsXml(track));
EasyMock.replay(retractJob);
DownloadDistributionService distributionService = EasyMock.createNiceMock(DownloadDistributionService.class);
// Make sure that all of the elements are distributed.
EasyMock.expect(distributionService.distribute(channelId, mediapackage, attachmentId, true)).andReturn(attachmentJob);
EasyMock.expect(distributionService.distribute(channelId, mediapackage, catalogId, true)).andReturn(catalogJob);
EasyMock.expect(distributionService.distribute(channelId, mediapackage, trackId, true)).andReturn(trackJob);
EasyMock.expect(distributionService.retract(channelId, mediapackage, channelId)).andReturn(retractJob);
EasyMock.replay(distributionService);
SecurityService securityService = EasyMock.createNiceMock(SecurityService.class);
EasyMock.expect(securityService.getOrganization()).andStubReturn(org);
EasyMock.replay(securityService);
ServiceRegistry serviceRegistry = EasyMock.createNiceMock(ServiceRegistry.class);
EasyMock.replay(serviceRegistry);
// Override the waitForStatus method to not block the jobs
ConfigurablePublishWorkflowOperationHandler configurePublish = new ConfigurablePublishWorkflowOperationHandler() {
@Override
protected Result waitForStatus(long timeout, Job... jobs) {
HashMap<Job, Status> map = Stream.mk(jobs).foldl(new HashMap<Job, Status>(), new Fn2<HashMap<Job, Status>, Job, HashMap<Job, Status>>() {
@Override
public HashMap<Job, Status> apply(HashMap<Job, Status> a, Job b) {
a.put(b, Status.FINISHED);
return a;
}
});
return new Result(map);
}
};
configurePublish.setDownloadDistributionService(distributionService);
configurePublish.setSecurityService(securityService);
configurePublish.setServiceRegistry(serviceRegistry);
WorkflowOperationResult result = configurePublish.start(workflowInstance, jobContext);
assertNotNull(result.getMediaPackage());
assertTrue("The publication element has not been added to the mediapackage.", capturePublication.hasCaptured());
assertTrue("Some other type of element has been added to the mediapackage instead of the publication element.", capturePublication.getValue().getElementType().equals(MediaPackageElement.Type.Publication));
Publication publication = (Publication) capturePublication.getValue();
assertEquals(1, publication.getAttachments().length);
assertNotEquals(attachment.getIdentifier(), publication.getAttachments()[0].getIdentifier());
attachment.setIdentifier(publication.getAttachments()[0].getIdentifier());
assertEquals(attachment, publication.getAttachments()[0]);
assertEquals(1, publication.getCatalogs().length);
assertNotEquals(catalog.getIdentifier(), publication.getCatalogs()[0].getIdentifier());
catalog.setIdentifier(publication.getCatalogs()[0].getIdentifier());
assertEquals(catalog, publication.getCatalogs()[0]);
assertEquals(1, publication.getTracks().length);
assertNotEquals(track.getIdentifier(), publication.getTracks()[0].getIdentifier());
track.setIdentifier(publication.getTracks()[0].getIdentifier());
assertEquals(track, publication.getTracks()[0]);
}
Aggregations