| /*=============================================================================# |
| # Copyright (c) 2005, 2021 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.ecommons.runtime.core.util; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| |
| |
| /** |
| * Creates text message like {@link org.eclipse.osgi.util.NLS} bind. |
| * |
| * This class is intent to use when creating messages repeatedly in a single thread. |
| * It is not thread safe. |
| */ |
| @NonNullByDefault |
| public class MessageBuilder { |
| |
| |
| private static final Object[] EMPTY_ARGS= new Object[0]; |
| |
| |
| private final StringBuilder builder; |
| |
| |
| public MessageBuilder() { |
| this(128); |
| } |
| |
| public MessageBuilder(final int initialBufferLength) { |
| this.builder= new StringBuilder(initialBufferLength); |
| } |
| |
| |
| /** |
| * Bind the given message's substitution locations with the given string value. |
| * |
| * @param message the message to be manipulated |
| * @param binding the object to be inserted into the message |
| * @return the manipulated String |
| * @throws IllegalArgumentException if the text appearing within curly braces in the given message does not map to an integer |
| */ |
| public String bind(final String message, final Object binding) { |
| return internalBind(message, null, String.valueOf(binding), null); |
| } |
| |
| /** |
| * Bind the given message's substitution locations with the given string values. |
| * |
| * @param message the message to be manipulated |
| * @param binding1 An object to be inserted into the message |
| * @param binding2 A second object to be inserted into the message |
| * @return the manipulated String |
| * @throws IllegalArgumentException if the text appearing within curly braces in the given message does not map to an integer |
| */ |
| public String bind(final String message, final Object binding1, final Object binding2) { |
| return internalBind(message, null, String.valueOf(binding1), String.valueOf(binding2)); |
| } |
| |
| /** |
| * Bind the given message's substitution locations with the given string values. |
| * |
| * @param message the message to be manipulated |
| * @param bindings An array of objects to be inserted into the message |
| * @return the manipulated String |
| * @throws IllegalArgumentException if the text appearing within curly braces in the given message does not map to an integer |
| */ |
| public String bind(final String message, final Object[] bindings) { |
| return internalBind(message, bindings, null, null); |
| } |
| |
| /* |
| * Perform the string substitution on the given message with the specified args. |
| * See the class comment for exact details. |
| */ |
| private String internalBind(final String message, Object[] args, final String argZero, final String argOne) { |
| if (message == null) { |
| return "No message available."; //$NON-NLS-1$ |
| } |
| if (args == null || args.length == 0) { |
| args= EMPTY_ARGS; |
| } |
| |
| this.builder.setLength(0); |
| |
| final int length= message.length(); |
| { int bufLen= length + (args.length * 5); |
| if (argZero != null) { |
| bufLen+= argZero.length() - 3; |
| if (argOne != null) { |
| bufLen+= argOne.length() - 3; |
| } |
| } |
| this.builder.ensureCapacity(bufLen); |
| } |
| for (int i= 0; i < length; i++) { |
| final char c= message.charAt(i); |
| switch (c) { |
| case '{' : |
| int index= message.indexOf('}', i); |
| // if we don't have a matching closing brace then... |
| if (index == -1) { |
| this.builder.append(c); |
| break; |
| } |
| i++; |
| if (i >= length) { |
| this.builder.append(c); |
| break; |
| } |
| // look for a substitution |
| int number= -1; |
| try { |
| number= Integer.parseInt(message.substring(i, index)); |
| } |
| catch (final NumberFormatException e) { |
| throw new IllegalArgumentException(e); |
| } |
| if (number == 0 && argZero != null) { |
| this.builder.append(argZero); |
| } |
| else if (number == 1 && argOne != null) { |
| this.builder.append(argOne); |
| } |
| else if (number >= 0 && number < args.length) { |
| this.builder.append(args[number]); |
| } |
| else { |
| this.builder.append("<missing argument>"); //$NON-NLS-1$ |
| } |
| i= index; |
| break; |
| case '\'' : |
| // if a single quote is the last char on the line then skip it |
| final int nextIndex= i + 1; |
| if (nextIndex >= length) { |
| this.builder.append(c); |
| break; |
| } |
| final char next= message.charAt(nextIndex); |
| // if the next char is another single quote then write out one |
| if (next == '\'') { |
| i++; |
| this.builder.append(c); |
| break; |
| } |
| // otherwise we want to read until we get to the next single quote |
| index= message.indexOf('\'', nextIndex); |
| // if there are no more in the string, then skip it |
| if (index == -1) { |
| this.builder.append(c); |
| break; |
| } |
| // otherwise write out the chars inside the quotes |
| this.builder.append(message.substring(nextIndex, index)); |
| i= index; |
| break; |
| default : |
| this.builder.append(c); |
| } |
| } |
| return this.builder.toString(); |
| } |
| |
| } |