001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
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.Writer;
021    
022    /**
023     * <p>
024     * See http://issues.liferay.com/browse/LPS-6072.
025     * </p>
026     *
027     * @author Shuyang Zhou
028     * @author Brian Wing Shun Chan
029     */
030    public class StringBundler {
031    
032            public StringBundler() {
033                    _array = new String[_DEFAULT_ARRAY_CAPACITY];
034            }
035    
036            public StringBundler(int initialCapacity) {
037                    if (initialCapacity <= 0) {
038                            throw new IllegalArgumentException();
039                    }
040    
041                    _array = new String[initialCapacity];
042            }
043    
044            public StringBundler(String s) {
045                    _array = new String[_DEFAULT_ARRAY_CAPACITY];
046    
047                    _array[0] = s;
048    
049                    _arrayIndex = 1;
050            }
051    
052            public StringBundler(String[] stringArray) {
053                    this(stringArray, 0);
054            }
055    
056            public StringBundler(String[] stringArray, int extraSpace) {
057                    _array = new String[stringArray.length + extraSpace];
058    
059                    for (int i = 0; i < stringArray.length; i++) {
060                            String s = stringArray[i];
061    
062                            if ((s != null) && (s.length() > 0)) {
063                                    _array[_arrayIndex++] = s;
064                            }
065                    }
066            }
067    
068            public StringBundler append(boolean b) {
069                    if (b) {
070                            return append(_TRUE);
071                    }
072                    else {
073                            return append(_FALSE);
074                    }
075            }
076    
077            public StringBundler append(char c) {
078                    return append(String.valueOf(c));
079            }
080    
081            public StringBundler append(char[] charArray) {
082                    if (charArray == null) {
083                            return append("null");
084                    }
085                    else {
086                            return append(new String(charArray));
087                    }
088            }
089    
090            public StringBundler append(double d) {
091                    return append(Double.toString(d));
092            }
093    
094            public StringBundler append(float f) {
095                    return append(Float.toString(f));
096            }
097    
098            public StringBundler append(int i) {
099                    return append(Integer.toString(i));
100            }
101    
102            public StringBundler append(long l) {
103                    return append(Long.toString(l));
104            }
105    
106            public StringBundler append(Object obj) {
107                    return append(String.valueOf(obj));
108            }
109    
110            public StringBundler append(String s) {
111                    if (s == null) {
112                            s = StringPool.NULL;
113                    }
114    
115                    if (s.length() == 0) {
116                            return this;
117                    }
118    
119                    if (_arrayIndex >= _array.length) {
120                            expandCapacity(_array.length * 2);
121                    }
122    
123                    _array[_arrayIndex++] = s;
124    
125                    return this;
126            }
127    
128            public StringBundler append(String[] stringArray) {
129                    if ((stringArray == null) || (stringArray.length == 0)) {
130                            return this;
131                    }
132    
133                    if ((_array.length - _arrayIndex) < stringArray.length) {
134                            expandCapacity((_array.length + stringArray.length) * 2);
135                    }
136    
137                    for (int i = 0; i < stringArray.length; i++) {
138                            String s = stringArray[i];
139    
140                            if ((s != null) && (s.length() > 0)) {
141                                    _array[_arrayIndex++] = s;
142                            }
143                    }
144    
145                    return this;
146            }
147    
148            public StringBundler append(StringBundler sb) {
149                    if ((sb == null) || (sb._arrayIndex == 0)) {
150                            return this;
151                    }
152    
153                    if ((_array.length - _arrayIndex) < sb._arrayIndex) {
154                            expandCapacity((_array.length + sb._arrayIndex) * 2);
155                    }
156    
157                    System.arraycopy(sb._array, 0, _array, _arrayIndex, sb._arrayIndex);
158    
159                    _arrayIndex += sb._arrayIndex;
160    
161                    return this;
162            }
163    
164            public int capacity() {
165                    return _array.length;
166            }
167    
168            public int index() {
169                    return _arrayIndex;
170            }
171    
172            public int length() {
173                    int length = 0;
174    
175                    for (int i = 0; i < _arrayIndex; i++) {
176                            length += _array[i].length();
177                    }
178    
179                    return length;
180            }
181    
182            public void setIndex(int newIndex) {
183                    if (newIndex < 0) {
184                            throw new ArrayIndexOutOfBoundsException(newIndex);
185                    }
186    
187                    if (newIndex > _array.length) {
188                            String[] newArray = new String[newIndex];
189    
190                            System.arraycopy(_array, 0, newArray, 0, _arrayIndex);
191    
192                            _array = newArray;
193                    }
194    
195                    if (_arrayIndex < newIndex) {
196                            for (int i = _arrayIndex; i < newIndex; i++) {
197                                    _array[i] = StringPool.BLANK;
198                            }
199                    }
200    
201                    if (_arrayIndex > newIndex) {
202                            for (int i = newIndex; i < _arrayIndex; i++) {
203                                    _array[i] = null;
204                            }
205                    }
206    
207                    _arrayIndex = newIndex;
208            }
209    
210            public void setStringAt(String s, int index) {
211                    if ((index < 0) || (index >= _arrayIndex)) {
212                            throw new ArrayIndexOutOfBoundsException(index);
213                    }
214    
215                    _array[index] = s;
216            }
217    
218            public String stringAt(int index) {
219                    if ((index < 0) || (index >= _arrayIndex)) {
220                            throw new ArrayIndexOutOfBoundsException(index);
221                    }
222    
223                    return _array[index];
224            }
225    
226            public String toString() {
227                    if (_arrayIndex == 0) {
228                            return StringPool.BLANK;
229                    }
230    
231                    if (_arrayIndex == 1) {
232                            return _array[0];
233                    }
234    
235                    if (_arrayIndex == 2) {
236                            return _array[0].concat(_array[1]);
237                    }
238    
239                    if (_arrayIndex == 3) {
240                            return _array[0].concat(_array[1]).concat(_array[2]);
241                    }
242    
243                    int length = 0;
244    
245                    for (int i = 0; i < _arrayIndex; i++) {
246                            length += _array[i].length();
247                    }
248    
249                    StringBuilder sb = null;
250    
251                    if (length > _threadLocalBufferLimit) {
252                            sb = _stringBuilderThreadLocal.get();
253    
254                            if (sb == null) {
255                                    sb = new StringBuilder(length);
256    
257                                    _stringBuilderThreadLocal.set(sb);
258                            }
259                            else if (sb.capacity() < length) {
260                                    sb.setLength(length);
261                            }
262    
263                            sb.setLength(0);
264                    }
265                    else {
266                            sb = new StringBuilder(length);
267                    }
268    
269                    for (int i = 0; i < _arrayIndex; i++) {
270                            sb.append(_array[i]);
271                    }
272    
273                    return sb.toString();
274            }
275    
276            public void writeTo(Writer writer) throws IOException {
277                    for (int i = 0; i < _arrayIndex; i++) {
278                            writer.write(_array[i]);
279                    }
280            }
281    
282            protected void expandCapacity(int newCapacity) {
283                    String[] newArray = new String[newCapacity];
284    
285                    System.arraycopy(_array, 0, newArray, 0, _arrayIndex);
286    
287                    _array = newArray;
288            }
289    
290            private static final int _DEFAULT_ARRAY_CAPACITY = 16;
291    
292            private static final String _FALSE = "false";
293    
294            private static final int _THREADLOCAL_BUFFER_LIMIT = GetterUtil.getInteger(
295                    System.getProperty(
296                            StringBundler.class.getName() + ".threadlocal.buffer.limit"));
297    
298            private static final String _TRUE = "true";
299    
300            private static ThreadLocal<StringBuilder> _stringBuilderThreadLocal;
301            private static int _threadLocalBufferLimit;
302    
303            static {
304                    if (_THREADLOCAL_BUFFER_LIMIT > 0) {
305                            _stringBuilderThreadLocal =
306                                    new SoftReferenceThreadLocal<StringBuilder>();
307                            _threadLocalBufferLimit = _THREADLOCAL_BUFFER_LIMIT;
308                    }
309                    else {
310                            _stringBuilderThreadLocal = null;
311                            _threadLocalBufferLimit = Integer.MAX_VALUE;
312                    }
313            }
314    
315            private String[] _array;
316            private int _arrayIndex;
317    
318    }