org.opencastproject.mediapackage.MediaPackageSupport Maven / Gradle / Ivy
/*
* 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.mediapackage;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.opencastproject.util.IoSupport.withResource;
import static org.opencastproject.util.data.Collections.list;
import static org.opencastproject.util.data.functions.Booleans.not;
import static org.opencastproject.util.data.functions.Options.sequenceOpt;
import static org.opencastproject.util.data.functions.Options.toOption;
import org.opencastproject.util.data.Effect;
import org.opencastproject.util.data.Function;
import org.opencastproject.util.data.Option;
import com.entwinemedia.fn.data.Opt;
import com.entwinemedia.fn.fns.Strings;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.net.URI;
import java.util.Collections;
import java.util.List;
/** Utility class used for media package handling. */
public final class MediaPackageSupport {
/** Disable construction of this utility class */
private MediaPackageSupport() {
}
private static final List NIL = java.util.Collections.EMPTY_LIST;
/**
* Mode used when merging media packages.
*
*
* Merge
assigns a new identifier in case of conflicts
* Replace
replaces elements in the target media package with matching identifier
* Skip
skips elements from the source media package with matching identifer
* Fail
fail in case of conflicting identifier
*
*/
public enum MergeMode {
Merge, Replace, Skip, Fail
}
/** the logging facility provided by log4j */
private static final Logger logger = LoggerFactory.getLogger(MediaPackageSupport.class.getName());
/**
* Merges the contents of media package located at sourceDir
into the media package located at
* targetDir
.
*
* When choosing to move the media package element into the new place instead of copying them, the source media
* package folder will be removed afterwards.
*
*
* @param dest
* the target media package directory
* @param src
* the source media package directory
* @param mode
* conflict resolution strategy in case of identical element identifier
* @throws MediaPackageException
* if an error occurs either accessing one of the two media packages or merging them
*/
public static MediaPackage merge(MediaPackage dest, MediaPackage src, MergeMode mode) throws MediaPackageException {
try {
for (MediaPackageElement e : src.elements()) {
if (dest.getElementById(e.getIdentifier()) == null)
dest.add(e);
else {
if (MergeMode.Replace == mode) {
logger.debug("Replacing element " + e.getIdentifier() + " while merging " + dest + " with " + src);
dest.remove(dest.getElementById(e.getIdentifier()));
dest.add(e);
} else if (MergeMode.Skip == mode) {
logger.debug("Skipping element " + e.getIdentifier() + " while merging " + dest + " with " + src);
continue;
} else if (MergeMode.Merge == mode) {
logger.debug("Renaming element " + e.getIdentifier() + " while merging " + dest + " with " + src);
e.setIdentifier(null);
dest.add(e);
} else if (MergeMode.Fail == mode) {
throw new MediaPackageException("Target media package " + dest + " already contains element with id "
+ e.getIdentifier());
}
}
}
} catch (UnsupportedElementException e) {
throw new MediaPackageException(e);
}
return dest;
}
/**
* Returns true
if the media package contains an element with the specified identifier.
*
* @param identifier
* the identifier
* @return true
if the media package contains an element with this identifier
*/
public static boolean contains(String identifier, MediaPackage mp) {
for (MediaPackageElement element : mp.getElements()) {
if (element.getIdentifier().equals(identifier))
return true;
}
return false;
}
/**
* Extract the file name from a media package elements URI.
*
* @return the file name or none if it could not be determined
*/
public static Opt getFileName(MediaPackageElement mpe) {
final URI uri = mpe.getURI();
if (uri != null) {
return Opt.nul(FilenameUtils.getName(uri.toString())).bind(Strings.blankToNone);
} else {
return Opt.none();
}
}
/**
* Create a copy of the given media package.
*
* ATTENTION: Copying changes the type of the media package elements, e.g. an element of
* type DublinCoreCatalog
will become a CatalogImpl
.
*/
public static MediaPackage copy(MediaPackage mp) {
return (MediaPackage) mp.clone();
}
/** Update a mediapackage element of a mediapackage. Mutates mp
. */
public static void updateElement(MediaPackage mp, MediaPackageElement e) {
mp.removeElementById(e.getIdentifier());
mp.add(e);
}
/** {@link #updateElement(MediaPackage, MediaPackageElement)} as en effect. */
public static Effect updateElement(final MediaPackage mp) {
return new Effect() {
@Override
protected void run(MediaPackageElement e) {
updateElement(mp, e);
}
};
}
public static final Function getMediaPackageElementId = new Function() {
@Override
public String apply(MediaPackageElement mediaPackageElement) {
return mediaPackageElement.getIdentifier();
}
};
/** Filters and predicates to work with media package element collections. */
public static final class Filters {
private Filters() {
}
// functions implemented for monadic bind in order to cast types
public static Function> byType(final Class type) {
return new Function>() {
@Override
public List apply(MediaPackageElement mpe) {
return type.isAssignableFrom(mpe.getClass()) ? list((A) mpe) : (List) NIL;
}
};
}
public static Function> byFlavor(
final MediaPackageElementFlavor flavor) {
return new Function>() {
@Override
public List apply(MediaPackageElement mpe) {
// match is commutative
return flavor.matches(mpe.getFlavor()) ? Collections.singletonList(mpe) : Collections.emptyList();
}
};
}
public static Function ofType(final Class type) {
return new Function() {
@Override
public Boolean apply(MediaPackageElement mpe) {
return type.isAssignableFrom(mpe.getClass());
}
};
}
public static final Function> presentations = byType(Publication.class);
public static final Function> attachments = byType(Attachment.class);
public static final Function> tracks = byType(Track.class);
public static final Function> catalogs = byType(Catalog.class);
public static final Function isPublication = ofType(Publication.class);
public static final Function isNotPublication = not(isPublication);
public static final Function hasChecksum = new Function() {
@Override
public Boolean apply(MediaPackageElement e) {
return e.getChecksum() != null;
}
};
public static final Function hasNoChecksum = not(hasChecksum);
public static final Function