Contents
About Torweg
Looking for a flexible shopping solution? pulse is so much more than just a CMS. It’s all for you.
Pulse is a framework that makes it simple to create websites and web applications. It is built on top of the Servlet API and uses Java technology, which means it can run on any platform where Java is supported. The first version of Pulse was created in May 2005 and has been updated regularly since then.
One of the key features of Pulse is its ease of use. Not only does it provide a simple way to build your own applications, but it also comes with a number of pre-built applications such as a content management system (CMS), an online store (Shop), and survey tools. These are all ready to use right away, so you don’t have to start from scratch when building your website.
Pulse also includes advanced features like a WebDAV based virtual file system for managing digital assets, mature user and role management, and flexible templating with XSLT 2.0/XPath
A few facts on pulse
The history of pulse
The whole story from the early plannings to where we are now.
Our Vision and Mission
We want to deliver the best solution for creating medium to large scale websites and browser based applications.
It’s all for you.
Copyright
pulse is licensed under the GPL v3. However pulse is build on top of other open source projects with various licenses. The icons used by pulse are non-free, please take note of their special license.
Legal Notice
What has to be said: who is responsible for the site, acknowledgements and how to reach us.
StringUtils.java
/*
2 * Copyright 2007 :torweg free software group
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18 package org.torweg.pulse.util;
19
20 import java.io.PrintWriter;
21 import java.math.BigInteger;
22 import java.security.MessageDigest;
23 import java.security.NoSuchAlgorithmException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.ListIterator;
30
31 import org.torweg.pulse.invocation.lifecycle.Lifecycle;
32 import org.torweg.pulse.util.io.FastStringWriter;
33
34 /**
35 * contains static utitity methods which are useful, when working with
36 * {@code String}s.
37 *
38 * @author Thomas Weber
39 * @version $Revision: 2022 $
40 */
41 public final class StringUtils {
42
43 /**
44 * the hexadecimal numbers.
45 */
46 private static final char[] HEX_NUMBERS = "0123456789ABCDEF".toCharArray();
47
48 /**
49 * the base 60 numbers.
50 */
51 private static final char[] BASE_62_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
52 .toCharArray();
53
54 /**
55 * 62.
56 */
57 private static final BigInteger SIXTY_TWO = BigInteger.valueOf(62L);
58
59 /**
60 * hidden default constructor.
61 */
62 private StringUtils() {
63 super();
64 }
65
66 /**
67 * returns the encoding of the given {@code String}.
68 *
69 * @param s
70 * the string to inspect
71 * @return the encoding
72 */
73 public static String getEncoding(final String s) {
74 return new java.io.InputStreamReader(new java.io.ByteArrayInputStream(
75 s.getBytes())).getEncoding();
76 }
77
78 /**
79 * turns a given {@code byte[]} into a string of hexadecimal numbers.
80 * <p>
81 * For example {@code 127, 126} get {@code FFFE}.
82 * </p>
83 *
84 * @param bs
85 * the bytes
86 * @return the hexadecimal string
87 */
88 public static String toHexString(final byte[] bs) {
89 StringBuilder hexString = new StringBuilder();
90 for (byte b : bs) {
91 int num = b + 128;
92 hexString.append(HEX_NUMBERS[num / 16]);
93 hexString.append(HEX_NUMBERS[num % 16]);
94 }
95 return hexString.toString();
96 }
97
98 /**
99 * returns a base 62 string for the given {@code BigInteger}.
100 *
101 * @param token
102 * the number to be converted
103 * @return the base 62 representation
104 */
105 public static String toBase62String(final BigInteger token) {
106 BigInteger temp = token;
107 StringBuilder base62String = new StringBuilder();
108 if ((token.signum() < 0)) {
109 base62String.append('-');
110 }
111 while (temp.abs().compareTo(SIXTY_TWO) > 0) {
112 base62String
113 .append(BASE_62_NUMBERS[temp.mod(SIXTY_TWO).intValue()]);
114 temp = temp.divide(SIXTY_TWO);
115 }
116 base62String.append(BASE_62_NUMBERS[temp.mod(SIXTY_TWO).intValue()]);
117 return base62String.toString();
118 }
119
120 /**
121 * returns a base 62 string for the given byte array.
122 *
123 * @param bytes
124 * the byte array
125 * @return the base 62 string
126 */
127 public static String toBase62String(final byte[] bytes) {
128 return toBase62String(new BigInteger(bytes));
129 }
130
131 /**
132 * returns the {@code BigInteger} represented by the given base 62 string.
133 *
134 * @param base62
135 * the base 62 encoded value
136 * @return the {@code BigInteger} represented by the given base 62 string
137 */
138 public static BigInteger fromBase62String(final String base62) {
139 BigInteger result = BigInteger.ZERO;
140 BigInteger base = BigInteger.ONE;
141 for (int i = 0; i < base62.length(); i++) {
142 char c = base62.charAt(i);
143 boolean found = false;
144 for (int k = 0; k < 62; k++) {
145 if (BASE_62_NUMBERS[k] == c) {
146 result = result.add(base.multiply(BigInteger.valueOf(k)));
147 found = true;
148 break;
149 }
150 }
151 if (!found) {
152 throw new NumberFormatException("Not a valid base 62 cypher: "
153 + c);
154 }
155 base = base.multiply(SIXTY_TWO);
156 }
157 return result;
158 }
159
160 /**
161 * hashes the given string using {@code <em>SHA-512</em>}.
162 *
163 * @param str
164 * the string
165 * @return the hash value as an hexadecimal string
166 * @throws NoSuchAlgorithmException
167 * if the hashing algorithm is not available
168 */
169 public static String digest16(final String str)
170 throws NoSuchAlgorithmException {
171 return digest16(str.getBytes());
172 }
173
174 /**
175 * hashes the byte[] using {@code <em>SHA-512</em>}.
176 *
177 * @param bytes
178 * the bytes
179 * @return the hash value as an hexadecimal string
180 * @throws NoSuchAlgorithmException
181 * if the hashing algorithm is not available
182 */
183 public static String digest16(final byte[] bytes)
184 throws NoSuchAlgorithmException {
185 return toHexString(MessageDigest.getInstance("SHA-512").digest(
186 Lifecycle.getSaltedHash(bytes)));
187 }
188
189 /**
190 * hashes the string using {@code <em>SHA-512</em>}.
191 *
192 * @param str
193 * the string
194 * @return the hash value as a base 62 string
195 * @throws NoSuchAlgorithmException
196 * if the hashing algorithm is not available
197 */
198 public static String digest62(final String str)
199 throws NoSuchAlgorithmException {
200 return digest62(str.getBytes());
201 }
202
203 /**
204 * hashes the byte[] using {@code <em>SHA-512</em>}.
205 *
206 * @param bytes
207 * the bytes
208 * @return the hash value as a base 62 string
209 * @throws NoSuchAlgorithmException
210 * if the hashing algorithm is not available
211 */
212 public static String digest62(final byte[] bytes)
213 throws NoSuchAlgorithmException {
214 return toBase62String(new BigInteger(MessageDigest.getInstance(
215 "SHA-512").digest(Lifecycle.getSaltedHash(bytes))));
216 }
217
218 /**
219 * returns the stack trace of the given {@code Throwable} as a string.
220 *
221 * @param t
222 * the throwable
223 * @return the stack trace of the given {@code Throwable} as a string
224 */
225 public static String getStackTrace(final Throwable t) {
226 FastStringWriter out = new FastStringWriter();
227 t.printStackTrace(new PrintWriter(out));
228 return out.toString();
229 }
230
231 /**
232 * Inserts a fraction-dot into the given string at after the given position
233 * (counting from the back) filling the string up with 0s (zeros) if too
234 * short.
235 *
236 * @param s
237 * the string to format
238 * @param pos
239 * the position to insert the fraction-dot
240 *
241 * @return the formatted string
242 */
243 public static String insertFractionDot(final String s, final int pos) {
244 return StringUtils.insertFromBack(s, pos, ".", "0").toString();
245 }
246
247 /**
248 * Inserts the given string <tt>insert</tt> at the specified position
249 * <tt>pos</tt> from the back of the string.
250 *
251 * @param s
252 * the string to be formatted
253 * @param pos
254 * the position
255 * @param insert
256 * the string to insert
257 * @param fill
258 * the fill
259 * @return a {@code StringBuilder}
260 */
261 public static StringBuilder insertFromBack(final String s, final int pos,
262 final String insert, final String fill) {
263 StringBuilder builder = new StringBuilder(s);
264 while (builder.length() <= pos) {
265 builder.insert(0, fill);
266 }
267 // if (builder.length() < pos) {
268 // return builder;
269 // }
270 return builder.reverse().insert(pos, insert).reverse();
271 }
272
273 /**
274 * ensures that the given {@code String} does not exceed the given maximum
275 * length, cutting off all characters exceeding characters.
276 * <p>
277 * {@code null} values will be converted to empty strings.
278 * </p>
279 *
280 * @param s
281 * the string
282 * @param l
283 * the maximum length
284 * @return a string that is guaranteed to be less than or equal in length to
285 * the given maximum length
286 */
287 public static String maxLength(final String s, final int l) {
288 if (s == null) {
289 return "";
290 }
291 if (s.length() <= l) {
292 return s;
293 }
294 return s.substring(0, l);
295 }
296
297 /**
298 * returns either the given object's string representation or "null", if the
299 * given object is {@code null}.
300 *
301 * @param o
302 * the object
303 * @return either the given object's string representation or "null", if the
304 * given object is {@code null}
305 */
306 public static String getString(final Object o) {
307 if (o == null) {
308 return "null";
309 }
310 return o.toString();
311 }
312
313 /**
314 * Simple {@code ListIterator<String>} that operates on a
315 * {@code String} split by a regex.
316 *
317 * @author Daniel Dietz
318 * @version $Revision: 2022 $
319 *
320 */
321 public static class StringElementIterator implements ListIterator<String>,
322 Iterable<String> {
323
324 /**
325 * The split-array the {@code StringElementIterator} operates on.
326 */
327 private final List<String> split;
328
329 /**
330 * The index.
331 */
332 private int index = -1;
333
334 /**
335 * Creates a new {@code StringElementIterator} for the given
336 * {@code String} and regex.
337 *
338 * @param string
339 * the {@code String}
340 * @param regex
341 * the regex for the split
342 */
343 public StringElementIterator(final String string, final String regex) {
344 super();
345 this.split = Arrays.asList(string.split(regex));
346 }
347
348 /**
349 * Creates a new reversed {@code StringElementIterator} for the given
350 * {@code String} and regex.
351 *
352 * @param string
353 * the {@code String}
354 * @param regex
355 * the regex for the split
356 * @param reverse
357 * flag, indicating whether the iterator shall process the
358 * split {@code String} in reverse order ( {@code true})
359 */
360 public StringElementIterator(final String string, final String regex,
361 final boolean reverse) {
362 super();
363 this.split = Arrays.asList(string.split(regex));
364 if (reverse) {
365 Collections.reverse(this.split);
366 }
367 }
368
369 /**
370 * Creates a new {@code StringElementIterator} which iterates over the
371 * given string array.
372 *
373 * @param stringArray
374 * the {@code String[]}
375 */
376 public StringElementIterator(final String[] stringArray) {
377 super();
378 this.split = Arrays.asList(stringArray);
379 }
380
381 /**
382 * Private copy constructor for {@link #iterator()}.
383 *
384 * @param s
385 * the list of string elements
386 */
387 private StringElementIterator(final List<String> s) {
388 super();
389 this.split = s;
390 }
391
392 /**
393 * Not implemented.
394 *
395 * @param o
396 * unused
397 *
398 * @throws UnsupportedOperationException
399 * always
400 *
401 * @see java.util.ListIterator#add(java.lang.Object)
402 */
403 public final void add(final String o)
404 throws UnsupportedOperationException {
405 throw new UnsupportedOperationException();
406 }
407
408 /**
409 * Returns whether the {@code StringElementIterator} has more elements.
410 *
411 * @return {@code true} if the {@code Iterator} has more elements,
412 * {@code false} otherwise
413 *
414 * @see java.util.ListIterator#hasNext()
415 */
416 public final boolean hasNext() {
417 return (this.index + 1 < this.split.size());
418 }
419
420 /**
421 * Returns whether the {@code StringElementIterator} has an element
422 * prior to the current element.
423 *
424 * @return {@code true} if the {@code Iterator} has previous elements,
425 * {@code false} otherwise
426 *
427 * @see java.util.ListIterator#hasPrevious()
428 */
429 public final boolean hasPrevious() {
430 return (this.index - 1 > -1);
431 }
432
433 /**
434 * Returns the next element.
435 *
436 * @return the next element
437 *
438 * @see java.util.ListIterator#next()
439 */
440 public final String next() {
441 this.index++;
442 try {
443 return this.split.get(this.index);
444 } catch (IndexOutOfBoundsException e) {
445 this.index = this.split.size() - 1;
446 throw e;
447 }
448 }
449
450 /**
451 * Returns the next index.
452 *
453 * @return the next index
454 *
455 * @see java.util.ListIterator#nextIndex()
456 */
457 public final int nextIndex() {
458 return (this.index + 1);
459 }
460
461 /**
462 * Returns the previous element.
463 *
464 * @return the previous element
465 *
466 * @see java.util.ListIterator#previous()
467 */
468 public final String previous() {
469 this.index--;
470 try {
471 return this.split.get(this.index);
472 } catch (IndexOutOfBoundsException e) {
473 this.index = -1;
474 throw e;
475 }
476 }
477
478 /**
479 * Returns the previous index.
480 *
481 * @return the previous index
482 *
483 * @see java.util.ListIterator#previousIndex()
484 */
485 public final int previousIndex() {
486 return (this.index - 1);
487 }
488
489 /**
490 * Not implemented.
491 *
492 * @throws UnsupportedOperationException
493 * always
494 *
495 * @see java.util.ListIterator#remove()
496 */
497 public final void remove() throws UnsupportedOperationException {
498 throw new UnsupportedOperationException(
499 "remove() not supported for: " + this);
500 }
501
502 /**
503 * Not implemented.
504 *
505 * @param o
506 * unused
507 *
508 * @throws UnsupportedOperationException
509 * always
510 *
511 * @see java.util.ListIterator#set(java.lang.Object)
512 */
513 public final void set(final String o)
514 throws UnsupportedOperationException {
515 throw new UnsupportedOperationException("set(" + o
516 + ") not supported for: " + this);
517 }
518
519 /**
520 * Returns a new {@code StringElementIterator} operating on a new
521 * instance of the internal list.
522 *
523 * @return this {@code StringElementIterator}
524 *
525 * @see java.lang.Iterable#iterator()
526 */
527 public final Iterator<String> iterator() {
528 return new StringElementIterator(new ArrayList<String>(this.split));
529 }
530
531 }
532
533 }