    001    // Copyright 2007, 2008, 2010 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5;
    016
    017    import java.util.List;
    018    import java.util.Map;
    019    import java.util.StringTokenizer;
    020
    021    import org.apache.tapestry5.internal.InternalConstants;
    022    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    023    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    024
    025    /**
    026     * Represents an HTTP content type. Allows to set various elements like the mime type, the character set, and other
    027     * parameters. This is similar to a number of other implementations of the same concept in JAF, etc. We have created
    028     * this simple implementation to avoid including the whole libraries.
    029     */
    030    public final class ContentType
    031    {
    032        private String baseType = "";
    033
    034        private String subType = "";
    035
    036        private final Map<String, String> parameters = CollectionFactory.newCaseInsensitiveMap();
    037
    038        /**
    039         * Creates a new empty content type.
    040         */
    041        public ContentType()
    042        {
    043        }
    044
    045        /**
    046         * Creates a new content type from the argument. The format of the argument has to be basetype/subtype(;key=value)*
    047         *
    048         * @param contentType the content type that needs to be represented
    049         */
    050        public ContentType(String contentType)
    051        {
    052            parse(contentType);
    053        }
    054
    055        /**
    056         * Creates a new content type with the given MIME type and charset
    057         */
    058        public ContentType(String contentType, String charset)
    059        {
    060            this(contentType);
    061
    062            setParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER, charset);
    063        }
    064
    065
    066        /**
    067         * Returns true only if the other object is another instance of ContentType, and has the ssame baseType, subType and
    068         * set of parameters.
    069         */
    070        @Override
    071        public boolean equals(Object o)
    072        {
    073            if (o == null) return false;
    074
    075            if (o.getClass() != this.getClass()) return false;
    076
    077            ContentType ct = (ContentType) o;
    078
    079            return baseType.equals(ct.baseType) && subType.equals(ct.subType) && parameters.equals(ct.parameters);
    080        }
    081
    082        /**
    083         * @return the base type of the content type
    084         */
    085        public String getBaseType()
    086        {
    087            return baseType;
    088        }
    089
    090        /**
    091         * @param baseType
    092         */
    093        public void setBaseType(String baseType)
    094        {
    095            assert baseType != null;
    096            this.baseType = baseType;
    097        }
    098
    099        /**
    100         * @return the sub-type of the content type
    101         */
    102        public String getSubType()
    103        {
    104            return subType;
    105        }
    106
    107        /**
    108         * @param subType
    109         */
    110        public void setSubType(String subType)
    111        {
    112            assert subType != null;
    113            this.subType = subType;
    114        }
    115
    116        /**
    117         * @return the MIME type of the content type
    118         */
    119        public String getMimeType()
    120        {
    121            return baseType + "/" + subType;
    122        }
    123
    124        /**
    125         * @return the list of names of parameters in this content type, in alphabetical order.
    126         */
    127        public List<String> getParameterNames()
    128        {
    129            return InternalUtils.sortedKeys(parameters);
    130        }
    131
    132        /**
    133         * @return the character set (the  "charset" parameter) or null.
    134         */
    135        public String getCharset()
    136        {
    137            return getParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER);
    138        }
    139
    140        /**
    141         * @param key the name of the content type parameter
    142         * @return the value of the content type parameter
    143         */
    144        public String getParameter(String key)
    145        {
    146            assert key != null;
    147            return parameters.get(key);
    148        }
    149
    150        /**
    151         * @param key   the name of the content type parameter
    152         * @param value the value of the content type parameter
    153         */
    154        public void setParameter(String key, String value)
    155        {
    156            assert key != null;
    157            assert value != null;
    158            parameters.put(key, value);
    159        }
    160
    161        /**
    162         * Parses the argument and configures the content type accordingly. The format of the argument has to be
    163         * type/subtype(;key=value)*
    164         *
    165         * @param contentType the content type that needs to be represented
    166         */
    167        public void parse(String contentType)
    168        {
    169            baseType = "";
    170            subType = "";
    171            parameters.clear();
    172
    173            StringTokenizer tokens = new StringTokenizer(contentType, ";");
    174            if (!tokens.hasMoreTokens()) return;
    175
    176            String mimeType = tokens.nextToken();
    177            StringTokenizer mimeTokens = new StringTokenizer(mimeType, "/");
    178            setBaseType(mimeTokens.hasMoreTokens() ? mimeTokens.nextToken() : "");
    179            setSubType(mimeTokens.hasMoreTokens() ? mimeTokens.nextToken() : "");
    180
    181            while (tokens.hasMoreTokens())
    182            {
    183                String parameter = tokens.nextToken();
    184
    185                StringTokenizer parameterTokens = new StringTokenizer(parameter, "=");
    186                String key = parameterTokens.hasMoreTokens() ? parameterTokens.nextToken() : "";
    187                String value = parameterTokens.hasMoreTokens() ? parameterTokens.nextToken() : "";
    188                setParameter(key, value);
    189            }
    190        }
    191
    192        /**
    193         * @return the string representation of this content type
    194         */
    195        public String unparse()
    196        {
    197            StringBuilder buffer = new StringBuilder(getMimeType());
    198
    199            for (String parameterName : getParameterNames())
    200            {
    201                buffer.append(";");
    202                buffer.append(parameterName);
    203                buffer.append("=");
    204                buffer.append(parameters.get(parameterName));
    205            }
    206
    207            return buffer.toString();
    208        }
    209
    210        /**
    211         * @return the string representation of this content type. Same as unparse().
    212         */
    213        @Override
    214        public String toString()
    215        {
    216            return unparse();
    217        }
    218    }