/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.engine.header;
import java.io.StringWriter;
import java.util.Collection;
import org.restlet.data.CharacterSet;
import org.restlet.data.Encoding;
import org.restlet.data.Reference;
import org.restlet.util.NamedValue;
/**
* HTTP-style header writer.
*
* @param <V>
* The value type.
* @author Jerome Louvel
*/
public abstract class HeaderWriter<V> extends StringWriter {
@Override
public HeaderWriter<V> append(char c) {
super.append(c);
return this;
}
/**
* Appends an array of characters.
*
* @param cs
* The array of characters.
* @return This writer.
*/
public HeaderWriter<V> append(char[] cs) {
if (cs != null) {
for (char c : cs) {
append(c);
}
}
return this;
}
@Override
public HeaderWriter<V> append(CharSequence csq) {
super.append(csq);
return this;
}
/**
* Appends a collection of values.
*
* @param values
* The collection of values to append.
* @return This writer.
*/
public HeaderWriter<V> append(Collection<V> values) {
if ((values != null) && !values.isEmpty()) {
boolean first = true;
for (V value : values) {
if (canWrite(value)) {
if (first) {
first = false;
} else {
appendValueSeparator();
}
append(value);
}
}
}
return this;
}
/**
* Appends an integer.
*
* @param i
* The value to append.
* @return This writer.
*/
public HeaderWriter<V> append(int i) {
return append(Integer.toString(i));
}
/**
* Appends a long.
*
* @param l
* The value to append.
* @return This writer.
*/
public HeaderWriter<V> append(long l) {
return append(Long.toString(l));
}
/**
* Appends a value.
*
* @param value
* The value.
* @return This writer.
*/
public abstract HeaderWriter<V> append(V value);
/**
* Appends a string as an HTTP comment, surrounded by parenthesis and with
* quoted pairs if needed.
*
* @param content
* The comment to write.
* @return This writer.
*/
public HeaderWriter<V> appendComment(String content) {
append('(');
char c;
for (int i = 0; i < content.length(); i++) {
c = content.charAt(i);
if (HeaderUtils.isCommentText(c)) {
append(c);
} else {
appendQuotedPair(c);
}
}
return append(')');
}
/**
* Formats and appends a parameter as an extension. If the value is not a
* token, then it is quoted.
*
* @param extension
* The parameter to format as an extension.
* @return This writer.
*/
public HeaderWriter<V> appendExtension(NamedValue<String> extension) {
if (extension != null) {
return appendExtension(extension.getName(), extension.getValue());
} else {
return this;
}
}
/**
* Appends an extension. If the value is not a token, then it is quoted.
*
* @param name
* The extension name.
* @param value
* The extension value.
* @return This writer.
*/
public HeaderWriter<V> appendExtension(String name, String value) {
if ((name != null) && (name.length() > 0)) {
append(name);
if ((value != null) && (value.length() > 0)) {
append("=");
if (HeaderUtils.isToken(value)) {
append(value);
} else {
appendQuotedString(value);
}
}
}
return this;
}
/**
* Appends a semicolon as a parameter separator.
*
* @return This writer.
*/
public HeaderWriter<V> appendParameterSeparator() {
return append(";");
}
/**
* Appends a product description.
*
* @param name
* The product name token.
* @param version
* The product version token.
* @return This writer.
*/
public HeaderWriter<V> appendProduct(String name, String version) {
appendToken(name);
if (version != null) {
append('/').appendToken(version);
}
return this;
}
/**
* Appends a quoted character, prefixing it with a backslash.
*
* @param character
* The character to quote.
* @return This writer.
*/
public HeaderWriter<V> appendQuotedPair(char character) {
return append('\\').append(character);
}
/**
* Appends a quoted string.
*
* @param content
* The string to quote and write.
* @return This writer.
*/
public HeaderWriter<V> appendQuotedString(String content) {
if ((content != null) && (content.length() > 0)) {
append('"');
char c;
for (int i = 0; i < content.length(); i++) {
c = content.charAt(i);
if (HeaderUtils.isQuotedText(c)) {
append(c);
} else {
appendQuotedPair(c);
}
}
append('"');
}
return this;
}
/**
* Appends a space character.
*
* @return This writer.
*/
public HeaderWriter<V> appendSpace() {
return append(' ');
}
/**
* Appends a token.
*
* @param token
* The token to write.
* @return This writer.
*/
public HeaderWriter<V> appendToken(String token) {
if (HeaderUtils.isToken(token)) {
return append(token);
} else {
throw new IllegalArgumentException(
"Unexpected character found in token: " + token);
}
}
/**
* Formats and appends a source string as an URI encoded string.
*
* @param source
* The source string to format.
* @param characterSet
* The supported character encoding.
* @return This writer.
*/
public HeaderWriter<V> appendUriEncoded(CharSequence source,
CharacterSet characterSet) {
return append(Reference.encode(source.toString(), characterSet));
}
/**
* Appends a comma as a value separator.
*
* @return This writer.
*/
public HeaderWriter<V> appendValueSeparator() {
return append(", ");
}
/**
* Indicates if the value can be written to the header. Useful to prevent
* the writing of {@link Encoding#IDENTITY} constants for example. By
* default it returns true for non null values.
*
* @param value
* The value to add.
* @return True if the value can be added.
*/
protected boolean canWrite(V value) {
return (value != null);
}
}