001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2010–2011 ApexIdentity Inc.
015 * Portions Copyright 2011-2014 ForgeRock AS.
016 */
017
018package org.forgerock.openig.header;
019
020import java.nio.charset.Charset;
021import java.util.List;
022
023import org.forgerock.openig.http.Message;
024
025/**
026 * Processes the <strong>{@code Content-Type}</strong> message header. For more information,
027 * see <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a> §14.17.
028 */
029public class ContentTypeHeader implements Header {
030
031    /** The name of the header that this object represents. */
032    public static final String NAME = "Content-Type";
033
034    /** The type/sub-type of the message. */
035    private String type = null;
036
037    /** The character set used in encoding the message. */
038    private String charset = null;
039
040    /** The boundary value provided in multipart messages. */
041    private String boundary = null;
042
043    /**
044     * Constructs a new empty header.
045     */
046    public ContentTypeHeader() {
047    }
048
049    /**
050     * Constructs a new header, initialized from the specified message.
051     *
052     * @param message the message to initialize the header from.
053     */
054    public ContentTypeHeader(Message<?> message) {
055        fromMessage(message);
056    }
057
058    /**
059     * Constructs a new header, initialized from the specified string value.
060     *
061     * @param string the value to initialize the header from.
062     */
063    public ContentTypeHeader(String string) {
064        fromString(string);
065    }
066
067    /**
068     * Returns the media type of the underlying data or {@code null} if none specified.
069     *
070     * @return The media type of the underlying data or {@code null} if none specified.
071     */
072    public String getType() {
073        return type != null ? type : null;
074    }
075
076    /**
077     * Returns the character set encoding used to encode the message, or {@code null} if no character set was specified.
078     *
079     * @throws java.nio.charset.IllegalCharsetNameException
080     *             if the given charset name is illegal.
081     * @throws java.nio.charset.UnsupportedCharsetException
082     *             if no support for the named charset is available.
083     * @return The character set encoding used to encode the message or {@code null} if empty.
084     */
085    public Charset getCharset() {
086        return charset != null ? Charset.forName(charset) : null;
087    }
088
089    /**
090     * Returns the encapsulation boundary or {@code null} if none specified.
091     *
092     * @return The encapsulation boundary or {@code null} if none specified.
093     */
094    public String getBoundary() {
095        return boundary != null ? boundary : null;
096    }
097
098    private void clear() {
099        type = null;
100        charset = null;
101        boundary = null;
102    }
103
104    @Override
105    public String getKey() {
106        return NAME;
107    }
108
109    @Override
110    public void fromMessage(Message<?> message) {
111        if (message != null && message.getHeaders() != null) {
112            fromString(message.getHeaders().getFirst(NAME));
113        }
114    }
115
116    @Override
117    public void fromString(String string) {
118        clear();
119        List<String> parts = HeaderUtil.split(string, ';');
120        if (parts.size() > 0) {
121            type = parts.get(0);
122            charset = HeaderUtil.parseParameters(parts).get("charset");
123            boundary = HeaderUtil.parseParameters(parts).get("boundary");
124        }
125    }
126
127    @Override
128    public void toMessage(Message<?> message) {
129        String value = toString();
130        if (value != null) {
131            message.getHeaders().putSingle(NAME, value);
132        }
133    }
134
135    @Override
136    public String toString() {
137        StringBuilder sb = new StringBuilder();
138        if (type != null) {
139            sb.append(type);
140            if (charset != null) {
141                sb.append("; charset=").append(charset);
142            }
143            if (boundary != null) {
144                sb.append("; boundary=").append(boundary);
145            }
146        }
147        return sb.length() > 0 ? sb.toString() : null;
148    }
149
150    @Override
151    public boolean equals(Object o) {
152        if (this == o) {
153            return true;
154        }
155        if (o == null || !(o instanceof ContentTypeHeader)) {
156            return false;
157        }
158        ContentTypeHeader ct = (ContentTypeHeader) o;
159        return ((type == null && ct.type == null)
160                || (type != null && type.equals(ct.type)))
161                && ((charset == null && ct.charset == null)
162                || (charset != null && charset.equals(ct.charset)))
163                && ((boundary == null && ct.boundary == null)
164                || (boundary != null && boundary.equals(ct.boundary)));
165    }
166
167    @Override
168    public int hashCode() {
169        return (type == null ? 0 : type.hashCode())
170                ^ (charset == null ? 0 : charset.hashCode())
171                ^ (boundary == null ? 0 : boundary.hashCode());
172    }
173}