OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
 * 
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each file.
 */
 
 /*
 * Copyright 2007-2009 Medsea Business Solutions S.L.
 * 
 * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
 * 
 * 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.openconcerto.utils.mime;

import java.io.Serializable;
import java.util.regex.Pattern;

/**
 * This class represents a simple MimeType object. A mime type is made up of two parts
 * <code>&lt;media type&gt;/&lt;sub type&gt;</code>. The media type can be something like
 * <code>application</code> or <code>text</code> and the the sub type can be something like
 * <code>xml</code> or <code>plain</code>.
 * 
 * Both the media type and sub type can also be the wild card <code>*</code> such as
 * <code>*&#47;*</code> and <code>text&#47;*</code>. Note, if the media type is the wild card then
 * the sub type must also be a wild card.
 * 
 * @author Steven McArdle
 * 
 */
public class MimeType implements Serializable {

    private static final long serialVersionUID = -1324243127744494894L;

    private static final Pattern mimeSplitter = Pattern.compile("[/;]++");

    protected String mediaType = "*";
    protected String subType = "*";

    // This is a estimate of how specific this mime type is
    private int specificity = 1;

    /**
     * Construct a MimeType from another MimeType instance
     * 
     * @param mimeType
     */
    public MimeType(final MimeType mimeType) {
        this.mediaType = mimeType.mediaType;
        this.subType = mimeType.subType;
        this.specificity = mimeType.specificity;
    }

    /**
     * Construct a mime type from a String such as <code>text/plain</code>. It tries to ensure that
     * the mime type pattern passed in is correctly formatted.
     * 
     * @param mimeType
     * @throws IllegalArgumentException
     */
    public MimeType(final String mimeType) throws IllegalArgumentException {
        if (mimeType == null || mimeType.trim().length() == 0) {
            throw new IllegalArgumentException("Invalid MimeType [" + mimeType + "]");
        }
        String[] parts = mimeSplitter.split(mimeType.trim());

        if (parts.length > 0) {
            // Treat as the mediaType
            mediaType = getValidMediaType(parts[0]);
        }
        if (parts.length > 1) {
            subType = getValidSubType(parts[1]);
        }
    }

    /**
     * Get the media type part of the mime type.
     * 
     * @return media type
     */
    public String getMediaType() {
        return mediaType;
    }

    /**
     * Get the sub type of the mime type
     * 
     * @return sub type
     */
    public String getSubType() {
        return subType;
    }

    /**
     * See if this MimeType is the same as the passed in mime type string
     * 
     * @param mimeType as a String
     * @return true if the MimeType passed in has the same media and sub types, else returns false.
     */
    private boolean match(final String mimeType) {
        return toString().equals(mimeType);
    }

    /**
     * Get the hashCode of this MimeType. The hashCode is calculate as (31 * mediaType.hashCode()) +
     * subType.hashCode()
     * 
     * @return calculated hashCode
     * @see Object#hashCode()
     */
    public int hashCode() {
        return (31 * mediaType.hashCode()) + subType.hashCode();
    }

    /**
     * Overrides the equals method of <code>java.lang.Object</code>. This is able to compare against
     * another MimeType instance or a string representation of a mime type.
     * 
     * @return true if the types match else false.
     * @see Object#equals(Object o)
     */
    public boolean equals(Object o) {
        if (o instanceof MimeType) {
            if (this.mediaType.equals(((MimeType) o).mediaType) && this.subType.equals(((MimeType) o).subType)) {
                return true;
            }
        } else if (o instanceof String) {
            return match((String) o);
        }
        return false;
    }

    /**
     * Overrides the toString method of <code>java.lang.Object</code>.
     * 
     * @return String representation i.e. <code>&lt;media type&gt;/&lt;sub type&gt;.
     * @see Object#toString()
     */
    public String toString() {
        return mediaType + "/" + subType;
    }

    /**
     * This indicates how specific the mime types is i.e. how good a match the mime type is when
     * returned from the getMimeTypes(...) calls.
     * <p>
     * This is calculated by the number of times this MimeType would be returned if the Collection
     * was not normalised. The higher the count the more MimeDetectors have matched this type. As
     * this can be a false positive for types such as application/octect-stream and text/plain where
     * they would be returned by multiple MimeDetector(s). These types are referred to as root mime
     * types where ALL mime types derive from application/octet-stream and all text/* types derive
     * from text/plan so in these cases we set the specificity to 0 no matter how many times they
     * match. This ensures they are regarded as the least specific in the returned Collection.
     * </p>
     * 
     * @return how specific this MimeType is according to the rest of the MimeTypes in a Collection.
     */
    public int getSpecificity() {
        return specificity;
    }

    /*
     * Set the value of the specificity. The higher the value the more specific a MimeType is.
     */
    void setSpecificity(final int specificity) {
        this.specificity = specificity;
    }

    /*
     * Check the media type at least looks valid. TODO: Enforce more rigorous checking of valid
     * media types.
     */
    private String getValidMediaType(final String mediaType) {
        if (mediaType == null || mediaType.trim().length() == 0) {
            return "*";
        }
        return mediaType;
    }

    /*
     * Check the sub type at least looks valid. TODO: Enforce more rigorous checking of valid sub
     * types.
     */
    private String getValidSubType(final String subType) {
        if (subType == null || subType.trim().length() == 0 || "*".equals(mediaType)) {
            // If the mediaType is a wild card then the sub type must also be a wild card
            return "*";
        }
        return subType;
    }
}