001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.memory.SoftReferenceThreadLocal;
018
019 import java.io.IOException;
020 import java.io.Serializable;
021 import java.io.Writer;
022
023
031 public class StringBundler implements Serializable {
032
033 public StringBundler() {
034 _array = new String[_DEFAULT_ARRAY_CAPACITY];
035 }
036
037 public StringBundler(int initialCapacity) {
038 if (initialCapacity <= 0) {
039 initialCapacity = _DEFAULT_ARRAY_CAPACITY;
040 }
041
042 _array = new String[initialCapacity];
043 }
044
045 public StringBundler(String s) {
046 _array = new String[_DEFAULT_ARRAY_CAPACITY];
047
048 _array[0] = s;
049
050 _arrayIndex = 1;
051 }
052
053 public StringBundler(String[] stringArray) {
054 this(stringArray, 0);
055 }
056
057 public StringBundler(String[] stringArray, int extraSpace) {
058 _array = new String[stringArray.length + extraSpace];
059
060 for (String s : stringArray) {
061 if ((s != null) && (s.length() > 0)) {
062 _array[_arrayIndex++] = s;
063 }
064 }
065 }
066
067 public StringBundler append(boolean b) {
068 if (b) {
069 return append(StringPool.TRUE);
070 }
071 else {
072 return append(StringPool.FALSE);
073 }
074 }
075
076 public StringBundler append(char c) {
077 return append(String.valueOf(c));
078 }
079
080 public StringBundler append(char[] chars) {
081 if (chars == null) {
082 return append("null");
083 }
084 else {
085 return append(new String(chars));
086 }
087 }
088
089 public StringBundler append(double d) {
090 return append(Double.toString(d));
091 }
092
093 public StringBundler append(float f) {
094 return append(Float.toString(f));
095 }
096
097 public StringBundler append(int i) {
098 return append(Integer.toString(i));
099 }
100
101 public StringBundler append(long l) {
102 return append(Long.toString(l));
103 }
104
105 public StringBundler append(Object obj) {
106 return append(String.valueOf(obj));
107 }
108
109 public StringBundler append(String s) {
110 if (s == null) {
111 s = StringPool.NULL;
112 }
113
114 if (s.length() == 0) {
115 return this;
116 }
117
118 if (_arrayIndex >= _array.length) {
119 expandCapacity(_array.length * 2);
120 }
121
122 _array[_arrayIndex++] = s;
123
124 return this;
125 }
126
127 public StringBundler append(String[] stringArray) {
128 if (ArrayUtil.isEmpty(stringArray)) {
129 return this;
130 }
131
132 if ((_array.length - _arrayIndex) < stringArray.length) {
133 expandCapacity((_array.length + stringArray.length) * 2);
134 }
135
136 for (String s : stringArray) {
137 if ((s != null) && (s.length() > 0)) {
138 _array[_arrayIndex++] = s;
139 }
140 }
141
142 return this;
143 }
144
145 public StringBundler append(StringBundler sb) {
146 if ((sb == null) || (sb._arrayIndex == 0)) {
147 return this;
148 }
149
150 if ((_array.length - _arrayIndex) < sb._arrayIndex) {
151 expandCapacity((_array.length + sb._arrayIndex) * 2);
152 }
153
154 System.arraycopy(sb._array, 0, _array, _arrayIndex, sb._arrayIndex);
155
156 _arrayIndex += sb._arrayIndex;
157
158 return this;
159 }
160
161 public int capacity() {
162 return _array.length;
163 }
164
165 public String[] getStrings() {
166 return _array;
167 }
168
169 public int index() {
170 return _arrayIndex;
171 }
172
173 public int length() {
174 int length = 0;
175
176 for (int i = 0; i < _arrayIndex; i++) {
177 length += _array[i].length();
178 }
179
180 return length;
181 }
182
183 public void setIndex(int newIndex) {
184 if (newIndex < 0) {
185 throw new ArrayIndexOutOfBoundsException(newIndex);
186 }
187
188 if (newIndex > _array.length) {
189 String[] newArray = new String[newIndex];
190
191 System.arraycopy(_array, 0, newArray, 0, _arrayIndex);
192
193 _array = newArray;
194 }
195
196 if (_arrayIndex < newIndex) {
197 for (int i = _arrayIndex; i < newIndex; i++) {
198 _array[i] = StringPool.BLANK;
199 }
200 }
201
202 if (_arrayIndex > newIndex) {
203 for (int i = newIndex; i < _arrayIndex; i++) {
204 _array[i] = null;
205 }
206 }
207
208 _arrayIndex = newIndex;
209 }
210
211 public void setStringAt(String s, int index) {
212 if ((index < 0) || (index >= _arrayIndex)) {
213 throw new ArrayIndexOutOfBoundsException(index);
214 }
215
216 _array[index] = s;
217 }
218
219 public String stringAt(int index) {
220 if ((index < 0) || (index >= _arrayIndex)) {
221 throw new ArrayIndexOutOfBoundsException(index);
222 }
223
224 return _array[index];
225 }
226
227 @Override
228 public String toString() {
229 if (_arrayIndex == 0) {
230 return StringPool.BLANK;
231 }
232
233 if (_arrayIndex == 1) {
234 return _array[0];
235 }
236
237 if (_arrayIndex == 2) {
238 return _array[0].concat(_array[1]);
239 }
240
241 if (_arrayIndex == 3) {
242 return _array[0].concat(_array[1]).concat(_array[2]);
243 }
244
245 int length = 0;
246
247 for (int i = 0; i < _arrayIndex; i++) {
248 length += _array[i].length();
249 }
250
251 StringBuilder sb = null;
252
253 if (length > _THREAD_LOCAL_BUFFER_LIMIT) {
254 sb = _stringBuilderThreadLocal.get();
255
256 if (sb == null) {
257 sb = new StringBuilder(length);
258
259 _stringBuilderThreadLocal.set(sb);
260 }
261 else if (sb.capacity() < length) {
262 sb.setLength(length);
263 }
264
265 sb.setLength(0);
266 }
267 else {
268 sb = new StringBuilder(length);
269 }
270
271 for (int i = 0; i < _arrayIndex; i++) {
272 sb.append(_array[i]);
273 }
274
275 return sb.toString();
276 }
277
278 public void writeTo(Writer writer) throws IOException {
279 for (int i = 0; i < _arrayIndex; i++) {
280 writer.write(_array[i]);
281 }
282 }
283
284 protected void expandCapacity(int newCapacity) {
285 String[] newArray = new String[newCapacity];
286
287 System.arraycopy(_array, 0, newArray, 0, _arrayIndex);
288
289 _array = newArray;
290 }
291
292 private static final int _DEFAULT_ARRAY_CAPACITY = 16;
293
294 private static final int _THREAD_LOCAL_BUFFER_LIMIT;
295
296 private static final ThreadLocal<StringBuilder> _stringBuilderThreadLocal;
297 private static final long serialVersionUID = 1L;
298
299 static {
300 int threadLocalBufferLimit = GetterUtil.getInteger(
301 System.getProperty(
302 StringBundler.class.getName() + ".threadlocal.buffer.limit"),
303 Integer.MAX_VALUE);
304
305 if ((threadLocalBufferLimit > 0) &&
306 (threadLocalBufferLimit < Integer.MAX_VALUE)) {
307
308 _THREAD_LOCAL_BUFFER_LIMIT = threadLocalBufferLimit;
309
310 _stringBuilderThreadLocal = new SoftReferenceThreadLocal<>();
311 }
312 else {
313 _THREAD_LOCAL_BUFFER_LIMIT = Integer.MAX_VALUE;
314
315 _stringBuilderThreadLocal = null;
316 }
317 }
318
319 private String[] _array;
320 private int _arrayIndex;
321
322 }