/**
* 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.util;
import static org.opencastproject.util.EqualsUtil.eqObj;
import static org.opencastproject.util.data.Collections.list;
import static org.opencastproject.util.data.Monadics.mlist;
import static org.opencastproject.util.data.Option.none;
import org.opencastproject.util.data.Collections;
import org.opencastproject.util.data.Function;
import org.opencastproject.util.data.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
* This class implements the mime type. Note that mime types should not be instantiated directly but be retreived from
* the mime type registry {@link MimeTypes}.
*/
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name = "mimetype", namespace = "http://mediapackage.opencastproject.org")
@XmlJavaTypeAdapter(MimeType.Adapter.class)
public final class MimeType implements Comparable<MimeType>, Serializable {
private static final Logger logger = LoggerFactory.getLogger(MimeType.class);
/** Serial version UID */
private static final long serialVersionUID = -2895494708659187394L;
/** String representation of type */
private final String type;
/** String representation of subtype */
private final String subtype;
/** Alternate representations for type/subtype */
private final List<MimeType> equivalents;
/** List of suffixes, the first is the main one. */
private final List<String> suffixes;
/** Main description */
private final Option<String> description;
/** The mime type flavor */
private final Option<String> flavor;
/** The mime type flavor description */
private final Option<String> flavorDescription;
/**
* Creates a new mime type with the given type and subtype.
*
* @param type
* the major type
* @param subtype
* minor type
*/
private MimeType(String type, String subtype, List<String> suffixes,
List<MimeType> equivalents,
Option<String> description,
Option<String> flavor, Option<String> flavorDescription) {
this.type = type;
this.subtype = subtype;
this.suffixes = suffixes;
this.equivalents = equivalents;
this.description = description;
this.flavor = flavor;
this.flavorDescription = flavorDescription;
}
public static MimeType mimeType(String type, String subtype, List<String> suffixes,
List<MimeType> equivalents,
Option<String> description,
Option<String> flavor, Option<String> flavorDescription) {
return new MimeType(type, subtype, suffixes, equivalents, description, flavor, flavorDescription);
}
public static MimeType mimeType(String type, String subtype, String suffix) {
return new MimeType(type, subtype, list(suffix), Collections.<MimeType>nil(), none(""), none(""), none(""));
}
public static MimeType mimeType(String type, String subtype) {
return new MimeType(type, subtype, Collections.<String>nil(), Collections.<MimeType>nil(), none(""), none(""), none(""));
}
/**
* Returns the major type of this mimetype.
* <p>
* For example, if the mimetype is ISO Motion JPEG 2000 which is represented as <code>video/mj2</code>, this method
* will return <code>video</code>.
*
* @return the type
*/
public String getType() {
return type;
}
/**
* Returns the minor type of this mimetype.
* <p>
* For example, if the mimetype is ISO Motion JPEG 2000 which is represented as <code>video/mj2</code>, this method
* will return <code>mj2</code>.
*
* @return the subtype
*/
public String getSubtype() {
return subtype;
}
/**
* Returns the main suffix for this mime type, that identifies files containing data of this flavor.
* <p>
* For example, files with the suffix <code>mj2</code> will contain data of type <code>video/mj2</code>.
*
* @return the file suffix
*/
public Option<String> getSuffix() {
return mlist(suffixes).headOpt();
}
/**
* Returns the registered suffixes for this mime type, that identify files containing data of this flavor. Note that
* the list includes the main suffix returned by <code>getSuffix()</code>.
* <p>
* For example, files containing ISO Motion JPEG 2000 may have file suffixes <code>mj2</code> and <code>mjp2</code>.
*
* @return the registered file suffixes
*/
public String[] getSuffixes() {
return suffixes.toArray(new String[suffixes.size()]);
}
/**
* Returns <code>true</code> if the mimetype supports the specified suffix.
*
* @return <code>true</code> if the suffix is supported
*/
public boolean supportsSuffix(String suffix) {
return suffixes.contains(suffix.toLowerCase());
}
/**
* Returns the mime type description.
*
* @return the description
*/
public Option<String> getDescription() {
return this.description;
}
/**
* Returns the flavor of this mime type.
* <p>
* A flavor is a hint on a specialized variant of a general mime type. For example, a dublin core file will have a
* mime type of <code>text/xml</code>. Adding a flavor of <code>mpeg-7</code> gives an additional hint on the file
* contents.
*
* @return the file's flavor
*/
public Option<String> getFlavor() {
return flavor;
}
/**
* Returns the flavor description.
*
* @return the flavor description
*/
public Option<String> getFlavorDescription() {
return flavorDescription;
}
/**
* Returns <code>true</code> if the file has the given flavor associated.
*
* @return <code>true</code> if the file has that flavor
*/
public boolean hasFlavor(String flavor) {
if (flavor == null)
return false;
return flavor.equalsIgnoreCase(flavor);
}
/**
* Returns the MimeType as a string of the form <code>type/subtype</code>
* @deprecated use {@link #toString()} instead
*/
public String asString() {
return toString();
}
/** Two mime types are considered equal if type and subtype are equal. */
public boolean eq(MimeType other) {
return eq(other.getType(), other.getSubtype());
}
/** Two mime types are considered equal if type and subtype are equal. */
public boolean eq(String type, String subtype) {
return this.type.equalsIgnoreCase(type) && this.subtype.equalsIgnoreCase(subtype);
}
/** {@link #eq(org.opencastproject.util.MimeType)} as a function. */
// CHECKSTYLE:OFF
public final Function<MimeType, Boolean> eq = new Function<MimeType, Boolean>() {
@Override public Boolean apply(MimeType other) {
return eq(other);
}
};
// CHECKSTYLE:ON
/**
* Returns <code>true</code> if this mime type is an equivalent for the specified type and subtype.
* <p>
* For example, a gzipped file may have both of these mime types defined, <code>application/x-compressed</code> or
* <code>application/x-gzip</code>.
*
* @return <code>true</code> if this mime type is equal
*/
public boolean isEquivalentTo(String type, String subtype) {
return eq(type, subtype) || mlist(equivalents).exists(eq);
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(MimeType m) {
return toString().compareTo(m.toString());
}
/**
* Returns the MimeType as a string of the form <code>type/subtype</code>
*/
@Override
public String toString() {
return type + "/" + subtype;
}
@Override
public int hashCode() {
return EqualsUtil.hash(type, subtype);
}
@Override
public boolean equals(Object that) {
return (this == that) || (that instanceof MimeType && eqFields((MimeType) that));
}
private boolean eqFields(MimeType that) {
return eqObj(this.type, that.type)
&& eqObj(this.subtype, that.subtype);
}
static class Adapter extends XmlAdapter<String, MimeType> {
@Override
public String marshal(MimeType mimeType) throws Exception {
return mimeType.type + "/" + mimeType.subtype;
}
@Override
public MimeType unmarshal(String str) throws Exception {
try {
return MimeTypes.parseMimeType(str);
} catch (Exception e) {
logger.info("unable to parse mimetype {}", str);
return null;
}
}
}
}