001    // Copyright 2004, 2005 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.tapestry.util;
016    
017    import java.util.HashMap;
018    import java.util.Map;
019    import java.util.Set;
020    import java.util.StringTokenizer;
021    
022    import org.apache.hivemind.util.Defense;
023    
024    /**
025     * Represents an HTTP content type. Allows to set various elements like the mime type, the character
026     * set, and other parameters. This is similar to a number of other implementations of the same
027     * concept in JAF, etc. We have created this simple implementation to avoid including the whole
028     * libraries.
029     * 
030     * @author mindbridge
031     * @since 3.0
032     */
033    public class ContentType
034    {
035        private String _baseType = "";
036    
037        private String _subType = "";
038    
039        private final Map _parameters = new HashMap();
040    
041        /**
042         * Creates a new empty content type.
043         */
044        public ContentType()
045        {
046        }
047    
048        /**
049         * Creates a new content type from the argument. The format of the argument has to be
050         * basetype/subtype(;key=value)*
051         * 
052         * @param contentType
053         *            the content type that needs to be represented
054         */
055        public ContentType(String contentType)
056        {
057            this();
058            parse(contentType);
059        }
060    
061        /**
062         * Returns true only if the other object is another instance of ContentType, and has the ssame
063         * baseType, subType and set of parameters.
064         */
065        public boolean equals(Object o)
066        {
067            if (o == null)
068                return false;
069    
070            if (o.getClass() != this.getClass())
071                return false;
072    
073            ContentType ct = (ContentType) o;
074    
075            return _baseType.equals(ct._baseType) && _subType.equals(ct._subType)
076                    && _parameters.equals(ct._parameters);
077        }
078    
079        /**
080         * @return the base type of the content type
081         */
082        public String getBaseType()
083        {
084            return _baseType;
085        }
086    
087        /**
088         * @param baseType
089         */
090        public void setBaseType(String baseType)
091        {
092            Defense.notNull(baseType, "baseType");
093    
094            _baseType = baseType;
095        }
096    
097        /**
098         * @return the sub-type of the content type
099         */
100        public String getSubType()
101        {
102            return _subType;
103        }
104    
105        /**
106         * @param subType
107         */
108        public void setSubType(String subType)
109        {
110            Defense.notNull(subType, "subType");
111    
112            _subType = subType;
113        }
114    
115        /**
116         * @return the MIME type of the content type
117         */
118        public String getMimeType()
119        {
120            return _baseType + "/" + _subType;
121        }
122    
123        /**
124         * @return the list of names of parameters in this content type
125         */
126        public String[] getParameterNames()
127        {
128            Set parameterNames = _parameters.keySet();
129            return (String[]) parameterNames.toArray(new String[parameterNames.size()]);
130        }
131    
132        /**
133         * @param key
134         *            the name of the content type parameter
135         * @return the value of the content type parameter
136         */
137        public String getParameter(String key)
138        {
139            Defense.notNull(key, "key");
140    
141            return (String) _parameters.get(key);
142        }
143    
144        /**
145         * @param key
146         *            the name of the content type parameter
147         * @param value
148         *            the value of the content type parameter
149         */
150        public void setParameter(String key, String value)
151        {
152            Defense.notNull(key, "key");
153            Defense.notNull(value, "value");
154    
155            _parameters.put(key.toLowerCase(), value);
156        }
157    
158        /**
159         * Parses the argument and configures the content type accordingly. The format of the argument
160         * has to be type/subtype(;key=value)*
161         * 
162         * @param contentType
163         *            the content type that needs to be represented
164         */
165        public void parse(String contentType)
166        {
167            _baseType = "";
168            _subType = "";
169            _parameters.clear();
170    
171            StringTokenizer tokens = new StringTokenizer(contentType, ";");
172            if (!tokens.hasMoreTokens())
173                return;
174    
175            String mimeType = tokens.nextToken();
176            StringTokenizer mimeTokens = new StringTokenizer(mimeType, "/");
177            setBaseType(mimeTokens.hasMoreTokens() ? mimeTokens.nextToken() : "");
178            setSubType(mimeTokens.hasMoreTokens() ? mimeTokens.nextToken() : "");
179    
180            while (tokens.hasMoreTokens())
181            {
182                String parameter = tokens.nextToken();
183    
184                StringTokenizer parameterTokens = new StringTokenizer(parameter, "=");
185                String key = parameterTokens.hasMoreTokens() ? parameterTokens.nextToken() : "";
186                String value = parameterTokens.hasMoreTokens() ? parameterTokens.nextToken() : "";
187                setParameter(key, value);
188            }
189        }
190    
191        /**
192         * @return the string representation of this content type
193         */
194        public String unparse()
195        {
196            StringBuffer buf = new StringBuffer(getMimeType());
197    
198            String[] parameterNames = getParameterNames();
199            for (int i = 0; i < parameterNames.length; i++)
200            {
201                String key = parameterNames[i];
202                String value = getParameter(key);
203                buf.append(";").append(key).append("=").append(value);
204            }
205    
206            return buf.toString();
207        }
208    
209        /**
210         * @return the string representation of this content type. Same as unparse().
211         */
212        public String toString()
213        {
214            return unparse();
215        }
216    
217    }