/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2009 Sun Microsystems, Inc. */ package com.sun.opends.sdk.util; import java.io.Serializable; import java.util.LinkedList; import java.util.List; import java.util.Locale; ; /** * A builder used specifically for messages. As messages are appended * they are translated to their string representation for storage using * the locale specified in the constructor. Note that before you use * this class you should consider whether it is appropriate. In general * composing messages by appending message to each other may not produce * a message that is formatted appropriately for all locales. It is * usually better to create messages by composition. In other words you * should create a base message that contains one or more string * argument specifiers (%s) and define other message objects to use as * replacement variables. In this way language translators have a change * to reformat the message for a particular locale if necessary. */ public final class MessageBuilder implements Appendable, CharSequence, Serializable { private static final long serialVersionUID = -3292823563904285315L; /** Used internally to store appended messages. */ private final StringBuilder sb = new StringBuilder(); /** Used internally to store appended messages. */ private final List messages = new LinkedList(); /** Used to render the string representation of appended messages. */ private final Locale locale; /** * Constructs an instance that will build messages in the default * locale. */ public MessageBuilder() { this(Locale.getDefault()); } /** * Constructs an instance that will build messages in the default * locale having an initial message. * * @param message * initial message */ public MessageBuilder(Message message) { this(Locale.getDefault()); append(message); } /** * Constructs an instance that will build messages in the default * locale having an initial message. * * @param message * initial message */ public MessageBuilder(String message) { this(Locale.getDefault()); append(message); } /** * Constructs an instance from another MessageBuilder. * * @param mb * from which to construct a new message builder */ public MessageBuilder(MessageBuilder mb) { for (Message msg : mb.messages) { this.messages.add(msg); } this.sb.append(sb); this.locale = mb.locale; } /** * Constructs an instance that will build messages in a specified * locale. * * @param locale * used for translating appended messages */ public MessageBuilder(Locale locale) { this.locale = locale; } /** * Append a message to this builder. The string representation of the * locale specifed in the constructor will be stored in this builder. * * @param message * to be appended * @return reference to this builder */ public MessageBuilder append(Message message) { if (message != null) { sb.append(message.toString(locale)); messages.add(message); } return this; } /** * Append an integer to this builder. * * @param number * to append * @return reference to this builder */ public MessageBuilder append(int number) { append(String.valueOf(number)); return this; } /** * Append an object to this builder. * * @param object * to append * @return reference to this builder */ public MessageBuilder append(Object object) { if (object != null) { append(String.valueOf(object)); } return this; } /** * Append a string to this builder. * * @param cs * to append * @return reference to this builder */ public MessageBuilder append(CharSequence cs) { if (cs != null) { sb.append(cs); if (cs instanceof Message) { messages.add((Message) cs); } else { messages.add(Message.raw(cs)); } } return this; } /** * Appends a subsequence of the specified character sequence to this * Appendable. *

* An invocation of this method of the form out.append(csq, start, * end) when csq is not null, behaves in * exactly the same way as the invocation * *

   * out.append(csq.subSequence(start, end))
   * 
* * @param csq * The character sequence from which a subsequence will be * appended. If csq is null, then * characters will be appended as if csq contained * the four characters "null". * @param start * The index of the first character in the subsequence * @param end * The index of the character following the last character in * the subsequence * @return A reference to this Appendable * @throws IndexOutOfBoundsException * If start or end are negative, * start is greater than end, or * end is greater than csq.length() */ public MessageBuilder append(CharSequence csq, int start, int end) throws IndexOutOfBoundsException { return append(csq.subSequence(start, end)); } /** * Appends the specified character to this Appendable. * * @param c * The character to append * @return A reference to this Appendable */ public MessageBuilder append(char c) { return append(String.valueOf(c)); } /** * Returns a string containing the characters in this sequence in the * same order as this sequence. The length of the string will be the * length of this sequence. * * @return a string consisting of exactly this sequence of characters */ public String toString() { return sb.toString(); } /** * Returns a string representation of the appended content in the * specific locale. Only Messages appended to this * builder are rendered in the requested locale. Raw strings appended * to this buffer are not translated to different locale. * * @param locale * requested * @return String representation */ public String toString(Locale locale) { StringBuilder sb = new StringBuilder(); for (Message m : messages) { sb.append(m.toString(locale)); } return sb.toString(); } /** * Returns a raw message representation of the appended content. * * @return Message raw message representing builder content */ public Message toMessage() { if (messages.isEmpty()) { return Message.EMPTY; } StringBuffer fmtString = new StringBuffer(); for (int i = 0; i < messages.size(); i++) { fmtString.append("%s"); } return Message.raw(fmtString, messages.toArray()); } /** * Returns the length of the string representation of this builder * using the default locale. * * @return the number of chars in this message */ public int length() { return length(Locale.getDefault()); } /** * Returns the char value at the specified index of the * string representation of this builder using the default locale. * * @param index * the index of the char value to be returned * @return the specified char value * @throws IndexOutOfBoundsException * if the index argument is negative or not less * than length() */ public char charAt(int index) throws IndexOutOfBoundsException { return charAt(Locale.getDefault(), index); } /** * Returns a new CharSequence that is a subsequence of * the string representation of this builder using the default locale. * The subsequence starts with the char value at the * specified index and ends with the char value at index * end - 1. The length (in chars) of the * returned sequence is end - start, so if * start == end then an empty sequence is returned. * * @param start * the start index, inclusive * @param end * the end index, exclusive * @return the specified subsequence * @throws IndexOutOfBoundsException * if start or end are negative, if * end is greater than length(), or if * start is greater than end */ public CharSequence subSequence(int start, int end) throws IndexOutOfBoundsException { return subSequence(Locale.getDefault(), start, end); } /** * Returns the length of the string representation of this builder * using a specific locale. * * @param locale * for which the rendering of this message will be used in * determining the length * @return the number of chars in this message */ public int length(Locale locale) { return toString(locale).length(); } /** * Returns the char value at the specified index of the * string representation of this builder using a specific locale. * * @param locale * for which the rendering of this message will be used in * determining the character * @param index * the index of the char value to be returned * @return the specified char value * @throws IndexOutOfBoundsException * if the index argument is negative or not less * than length() */ public char charAt(Locale locale, int index) throws IndexOutOfBoundsException { return toString(locale).charAt(index); } /** * Returns a new CharSequence that is a subsequence of * the string representation of this builder using a specific locale. * The subsequence starts with the char value at the * specified index and ends with the char value at index * end - 1. The length (in chars) of the * returned sequence is end - start, so if * start == end then an empty sequence is returned. * * @param locale * for which the rendering of this message will be used in * determining the character * @param start * the start index, inclusive * @param end * the end index, exclusive * @return the specified subsequence * @throws IndexOutOfBoundsException * if start or end are negative, if * end is greater than length(), or if * start is greater than end */ public CharSequence subSequence(Locale locale, int start, int end) throws IndexOutOfBoundsException { return toString(locale).subSequence(start, end); } }