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
015package org.apache.tapestry5;
016
017import java.util.List;
018import java.util.Map;
019import java.util.StringTokenizer;
020
021import org.apache.tapestry5.internal.InternalConstants;
022import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
023import 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 */
030public 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}