You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2010/11/05 01:01:06 UTC

svn commit: r1031360 - in /myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util: ArrayUtils.java LocaleUtils.java RendererUtils.java StringUtils.java

Author: lu4242
Date: Fri Nov  5 00:01:06 2010
New Revision: 1031360

URL: http://svn.apache.org/viewvc?rev=1031360&view=rev
Log:
MFCOMMONS-15 Move and document some very useful classes from shared to myfaces commons utils

Added:
    myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/ArrayUtils.java
    myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/LocaleUtils.java
    myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/RendererUtils.java
    myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/StringUtils.java

Added: myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/ArrayUtils.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/ArrayUtils.java?rev=1031360&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/ArrayUtils.java (added)
+++ myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/ArrayUtils.java Fri Nov  5 00:01:06 2010
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.commons.util;
+
+import java.lang.reflect.Array;
+
+/**
+ * Utility class for managing arrays
+ *
+ * @since 1.0.1
+ * @author Anton Koinov (latest modification by $Author: matzew $)
+ * @version $Revision: 557350 $ $Date: 2007-07-18 13:19:50 -0500 (mié, 18 jul 2007) $
+ */
+public final class ArrayUtils
+{
+    public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+    public static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    protected ArrayUtils()
+    {
+        // hide from public access
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    private static Class commonClass(Class c1, Class c2)
+    {
+        if (c1 == c2)
+        {
+            return c1;
+        }
+
+        if ((c1 == Object.class) || c1.isAssignableFrom(c2))
+        {
+            return c1;
+        }
+
+        if (c2.isAssignableFrom(c1))
+        {
+            return c2;
+        }
+
+        if (c1.isPrimitive() || c2.isPrimitive())
+        {
+            // REVISIT: we could try to autoconvert to Object or something appropriate
+            throw new IllegalArgumentException("incompatible types " + c1 + " and " + c2);
+        }
+
+        // REVISIT: we could try to find a common supper class or interface
+        return Object.class;
+    }
+
+    /**
+     * Concatenates two arrays into one. If arr1 is null or empty, returns arr2.
+     * If arr2 is null or empty, returns arr1. May return null if both arrays are null,
+     * or one is empty and the other null. <br>
+     * The concatenated array has componentType which is compatible with both input arrays (or Object[])
+     *
+     * @param arr1 input array
+     * @param arr2 input array
+     *
+     * @return Object the concatenated array, elements of arr1 first
+     */
+    public static Object concat(Object arr1, Object arr2)
+    {
+        int len1 = (arr1 == null) ? (-1) : Array.getLength(arr1);
+
+        if (len1 <= 0)
+        {
+            return arr2;
+        }
+
+        int len2 = (arr2 == null) ? (-1) : Array.getLength(arr2);
+
+        if (len2 <= 0)
+        {
+            return arr1;
+        }
+
+        Class  commonComponentType =
+            commonClass(arr1.getClass().getComponentType(), arr2.getClass().getComponentType());
+        Object newArray = Array.newInstance(commonComponentType, len1 + len2);
+        System.arraycopy(arr1, 0, newArray, 0, len1);
+        System.arraycopy(arr2, 0, newArray, len1, len2);
+
+        return newArray;
+    }
+
+    /**
+     * Concatenates arrays into one. Any null or empty arrays are ignored.
+     * If all arrays are null or empty, returns null.
+     * Elements will be ordered in the order in which the arrays are supplied.
+     *
+     * @param arrs array of arrays
+     * @return the concatenated array
+     */
+    public static Object concat(Object[] arrs)
+    {
+        int   totalLen            = 0;
+        Class commonComponentType = null;
+        for (int i = 0, len = arrs.length; i < len; i++)
+        {
+            // skip all null arrays
+            if (arrs[i] == null)
+            {
+                continue;
+            }
+
+            int arrayLen = Array.getLength(arrs[i]);
+
+            // skip all empty arrays
+            if (arrayLen == 0)
+            {
+                continue;
+            }
+
+            totalLen += arrayLen;
+
+            Class componentType = arrs[i].getClass().getComponentType();
+            commonComponentType =
+                (commonComponentType == null) ? componentType
+                                              : commonClass(commonComponentType, componentType);
+        }
+
+        if (commonComponentType == null)
+        {
+            return null;
+        }
+
+        return concat(Array.newInstance(commonComponentType, totalLen), totalLen, arrs);
+    }
+
+    public static Object concat(Object toArray, int totalLen, Object[] arrs)
+    {
+        if (totalLen == 0)
+        {
+            // Should we allocate an empty array instead?
+            return toArray;
+        }
+
+        if (totalLen > Array.getLength(toArray))
+        {
+            toArray = Array.newInstance(toArray.getClass().getComponentType(), totalLen);
+        }
+
+        for (int i = 0, len = arrs.length, offset = 0; i < len; i++)
+        {
+            final Object arr = arrs[i];
+            if (arr != null)
+            {
+                int arrayLen = Array.getLength(arr);
+                if (arrayLen > 0)
+                {
+                    System.arraycopy(arr, 0, toArray, offset, arrayLen);
+                    offset += arrayLen;
+                }
+            }
+        }
+
+        return toArray;
+    }
+
+    public static Object concat(Object arr1, Object arr2, Object arr3)
+    {
+        return concat(new Object[] {arr1, arr2, arr3});
+    }
+
+    public static Object concat(Object arr1, Object arr2, Object arr3, Object arr4)
+    {
+        return concat(new Object[] {arr1, arr2, arr3, arr4});
+    }
+
+    public static Object concat(Object arr1, Object arr2, Object arr3, Object arr4, Object arr5)
+    {
+        return concat(new Object[] {arr1, arr2, arr3, arr4, arr5});
+    }
+
+    public static Object concatSameType(Object toArray, Object[] arrs)
+    {
+        int totalLen = 0;
+        for (int i = 0, len = arrs.length; i < len; i++)
+        {
+            if (arrs[i] != null)
+            {
+                totalLen += Array.getLength(arrs[i]);
+            }
+        }
+
+        return concat(toArray, totalLen, arrs);
+    }
+
+    public static boolean contains(Object[] array, Object value)
+    {
+        if (array == null || array.length == 0)
+        {
+            return false;
+        }
+
+        for (int i = 0; i < array.length; i++)
+        {
+            Object o = array[i];
+            if ((o == null && value == null) ||
+                (o != null && o.equals(value)))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

Added: myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/LocaleUtils.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/LocaleUtils.java?rev=1031360&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/LocaleUtils.java (added)
+++ myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/LocaleUtils.java Fri Nov  5 00:01:06 2010
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.commons.util;
+
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * @since 1.0.1
+ * @author Anton Koinov (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public final class LocaleUtils
+{
+    private static final Log log = LogFactory.getLog(LocaleUtils.class);
+
+    /** Utility class, do not instatiate */
+    private LocaleUtils()
+    {
+        // utility class, do not instantiate
+    }
+
+    /**
+     * Converts a locale string to <code>Locale</code> class. Accepts both
+     * '_' and '-' as separators for locale components.
+     *
+     * @param localeString string representation of a locale
+     * @return Locale instance, compatible with the string representation
+     */
+    public static Locale toLocale(String localeString)
+    {
+        if ((localeString == null) || (localeString.length() == 0))
+        {
+            Locale locale = Locale.getDefault();
+            if(log.isWarnEnabled())
+                log.warn("Locale name in faces-config.xml null or empty, setting locale to default locale : "+locale.toString());
+            return locale;
+        }
+
+        int separatorCountry = localeString.indexOf('_');
+        char separator;
+        if (separatorCountry >= 0) {
+            separator = '_';
+        }
+        else
+        {
+            separatorCountry = localeString.indexOf('-');
+            separator = '-';
+        }
+
+        String language, country, variant;
+        if (separatorCountry < 0)
+        {
+            language = localeString;
+            country = variant = "";
+        }
+        else
+        {
+            language = localeString.substring(0, separatorCountry);
+
+            int separatorVariant = localeString.indexOf(separator, separatorCountry + 1);
+            if (separatorVariant < 0)
+            {
+                country = localeString.substring(separatorCountry + 1);
+                variant = "";
+            }
+            else
+            {
+                country = localeString.substring(separatorCountry + 1, separatorVariant);
+                variant = localeString.substring(separatorVariant + 1);
+            }
+        }
+
+        return new Locale(language, country, variant);
+    }
+
+
+    /**
+     * Convert locale string used by converter tags to locale.
+     *
+     * @param name name of the locale
+     * @return locale specified by the given String
+     */
+    public static Locale converterTagLocaleFromString(String name)
+    {
+        try
+        {
+            Locale locale;
+            StringTokenizer st = new StringTokenizer(name, "_");
+            String language = st.nextToken();
+
+            if(st.hasMoreTokens())
+            {
+                String country = st.nextToken();
+
+                if(st.hasMoreTokens())
+                {
+                    String variant = st.nextToken();
+                    locale = new Locale(language, country, variant);
+                }
+                else
+                {
+                    locale = new Locale(language, country);
+                }
+            }
+            else
+            {
+                locale = new Locale(language);
+            }
+
+
+            return locale;
+        }
+        catch(Exception e)
+        {
+            throw new IllegalArgumentException("Locale parsing exception - " +
+                "invalid string representation '" + name + "'");
+        }
+    }
+}

Added: myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/RendererUtils.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/RendererUtils.java?rev=1031360&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/RendererUtils.java (added)
+++ myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/RendererUtils.java Fri Nov  5 00:01:06 2010
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.commons.util;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * 
+ * @author Leonardo Uribe
+ * @since 1.0.1
+ */
+public class RendererUtils
+{
+
+    public static void renderChildren(FacesContext facesContext, UIComponent component)
+            throws IOException
+    {
+        if (component.getChildCount() > 0)
+        {
+            for (Iterator it = component.getChildren().iterator(); it.hasNext(); )
+            {
+                UIComponent child = (UIComponent)it.next();
+                renderChild(facesContext, child);
+            }
+        }
+    }
+
+
+    public static void renderChild(FacesContext facesContext, UIComponent child)
+            throws IOException
+    {
+        if (!child.isRendered())
+        {
+            return;
+        }
+
+        child.encodeBegin(facesContext);
+        if (child.getRendersChildren())
+        {
+            child.encodeChildren(facesContext);
+        }
+        else
+        {
+            renderChildren(facesContext, child);
+        }
+        child.encodeEnd(facesContext);
+    }
+
+}

Added: myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/StringUtils.java
URL: http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/StringUtils.java?rev=1031360&view=auto
==============================================================================
--- myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/StringUtils.java (added)
+++ myfaces/commons/trunk/myfaces-commons-utils/src/main/java/org/apache/myfaces/commons/util/StringUtils.java Fri Nov  5 00:01:06 2010
@@ -0,0 +1,710 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.commons.util;
+
+import java.util.ArrayList;
+
+
+/**
+ * Implements utility functions for the String class
+ *
+ * <p>
+ * Emphasis on performance and reduced memory allocation/garbage collection
+ * in exchange for longer more complex code.
+ * </p>
+ *
+ * @since 1.0.1
+ * @author Anton Koinov (latest modification by $Author: skitching $)
+ * @version $Revision: 673827 $ $Date: 2008-07-03 16:46:23 -0500 (jue, 03 jul 2008) $
+ */
+public final class StringUtils
+{
+    private StringUtils()
+    {
+        // utility class, no instantiation
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Checks that the string represents a floating point number that CANNOT be
+     * in exponential notation
+     *
+     * @param str the string to check
+     *
+     * @return boolean
+     */
+    public static boolean isFloatNoExponent(String str)
+    {
+        int len = str.length();
+        if (len == 0)
+        {
+            return false;
+        }
+
+        // skip first char if sign char
+        char c = str.charAt(0);
+        int  i = ((c == '-') || (c == '+')) ? 1 : 0;
+
+        // is it only a sign?
+        if (i >= len)
+        {
+            return false;
+        }
+
+        boolean decimalPointFound = false;
+
+        do
+        {
+            c = str.charAt(i);
+            if (c == '.')
+            {
+                // is this a second dot?
+                if (decimalPointFound)
+                {
+                    return false;
+                }
+
+                decimalPointFound = true;
+            }
+            else if (!Character.isDigit(c))
+            {
+                return false;
+            }
+
+            i++;
+        }
+        while (i < len);
+
+        return true;
+    }
+
+    public static boolean isFloatWithOptionalExponent(String str)
+    {
+        int len = str.length();
+        if (len == 0)
+        {
+            return false;
+        }
+
+        // skip first char if sign char
+        char c = str.charAt(0);
+        int  i = ((c == '-') || (c == '+')) ? 1 : 0;
+
+        // is it only a sign?
+        if (i >= len)
+        {
+            return false;
+        }
+
+        boolean exponentFound     = false;
+        boolean decimalPointFound = false;
+
+        do
+        {
+            c = str.charAt(i);
+            switch (c)
+            {
+                case '.':
+
+                    // is this a second one, are we in the exponent?
+                    if (decimalPointFound || exponentFound)
+                    {
+                        return false;
+                    }
+                    decimalPointFound = true;
+
+                    break;
+
+                case 'e':
+                case 'E':
+
+                    // is this a second one?
+                    if (exponentFound)
+                    {
+                        return false;
+                    }
+                    exponentFound = true;
+
+                    // check for exponent sign
+                    c = str.charAt(i + 1);
+
+                    if ((c == '-') || (c == '+'))
+                    {
+                        i++;
+                    }
+
+                    break;
+
+                default:
+                    if (!Character.isDigit(c))
+                    {
+                        return false;
+                    }
+            }
+
+            i++;
+        }
+        while (i < len);
+
+        return true;
+    }
+
+    public static boolean isInteger(String str)
+    {
+        int len = str.length();
+        if (len == 0)
+        {
+            return false;
+        }
+
+        // skip first char if sign char
+        char c = str.charAt(0);
+        int  i = ((c == '-') || (c == '+')) ? 1 : 0;
+
+        // is it only a sign?
+        if (i >= len)
+        {
+            return false;
+        }
+
+        do
+        {
+            if (!Character.isDigit(str.charAt(i)))
+            {
+                return false;
+            }
+            i++;
+        }
+        while (i < len);
+
+        return true;
+    }
+
+    public static boolean isUnsignedInteger(String str)
+    {
+        int len = str.length();
+        if (len == 0)
+        {
+            return false;
+        }
+
+        for (int i = 0; i < len; i++)
+        {
+            if (!Character.isDigit(str.charAt(i)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Undoubles the quotes inside the string <br> Example:<br>
+     * <pre>
+     * hello""world becomes hello"world
+     * </pre>
+     *
+     * @param str input string to dequote
+     * @param quote the quoting char
+     *
+     * @return dequoted string
+     */
+    public static String dequote(String str, char quote)
+    {
+        // Is there anything to dequote?
+        if (str == null)
+        {
+            return null;
+        }
+
+        return dequote(str, 0, str.length(), quote);
+    }
+
+    /**
+     * Undoubles the quotes inside a substring <br> Example:<br>
+     * <pre>
+     * hello""world becomes hello"world
+     * </pre>
+     * WARNING: scan for quote may continue to the end of the string, make sure
+     * that either <code>charAt(end + 1) == quote</code> or <code>end =
+     * str.lentgth()</code>. If in doubt call
+     * <code>dequote(str.substring(begin, end), quote)</code>
+     *
+     * @param str input string from which to get the substring, must not be
+     *        null
+     * @param begin begin index for substring
+     * @param end end index for substring
+     * @param quote the quoting char
+     *
+     * @return dequoted string
+     *
+     * @throws IllegalArgumentException if string is incorrectly quoted
+     */
+    public static String dequote(String str, int begin, int end, char quote)
+    {
+        // Is there anything to dequote?
+        if (begin == end)
+        {
+            return "";
+        }
+
+        int end_ = str.indexOf(quote, begin);
+
+        // If no quotes, return the original string
+        // and save StringBuffer allocation/char copying
+        if (end_ < 0)
+        {
+            return str.substring(begin, end);
+        }
+
+        StringBuffer sb     = new StringBuffer(end - begin);
+        int          begin_ = begin; // need begin later
+        for (; (end_ >= 0) && (end_ < end);
+            end_ = str.indexOf(quote, begin_ = end_ + 2))
+        {
+            if (((end_ + 1) >= end) || (str.charAt(end_ + 1) != quote))
+            {
+                throw new IllegalArgumentException(
+                    "Internal quote not doubled in string '"
+                    + str.substring(begin, end) + "'");
+            }
+
+            sb.append(substring(str, begin_, end_)).append(quote);
+        }
+
+        return sb.append(substring(str, begin_, end)).toString();
+    }
+
+    /**
+     * Removes the surrounding quote and any double quote inside the string <br>
+     * Example:<br>
+     * <pre>
+     * "hello""world" becomes hello"world
+     * </pre>
+     *
+     * @param str input string to dequote
+     * @param quote the quoting char
+     *
+     * @return dequoted String
+     */
+    public static String dequoteFull(String str, char quote)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+
+        return dequoteFull(str, 0, str.length(), quote);
+    }
+
+    public static String dequoteFull(String str, int begin, int end, char quote)
+    {
+        // If empty substring, return empty string
+        if (begin == end)
+        {
+            return "";
+        }
+
+        // If not quoted, return string
+        if (str.charAt(begin) != quote)
+        {
+            return str.substring(begin, end);
+        }
+
+        int _end = end - 1;
+        if ((str.length() < 2) || (str.charAt(_end) != quote))
+        {
+            throw new IllegalArgumentException(
+                "Closing quote missing in string '"
+                + substring(str, begin, end) + "'");
+        }
+
+        return dequote(str, begin + 1, _end, quote);
+    }
+
+    public static String replace(String str, String repl, String with)
+    {
+        int lastindex = 0;
+        int pos = str.indexOf(repl);
+
+        // If no replacement needed, return the original string
+        // and save StringBuffer allocation/char copying
+        if (pos < 0)
+        {
+            return str;
+        }
+
+        int          len     = repl.length();
+        int          lendiff = with.length() - repl.length();
+        StringBuffer out     =
+            new StringBuffer((lendiff <= 0) ? str.length()
+                : (str.length() + (10 * lendiff)));
+        for (; pos >= 0; pos = str.indexOf(repl, lastindex = pos + len))
+        {
+            out.append(substring(str, lastindex, pos)).append(with);
+        }
+
+        return out.append(substring(str, lastindex, str.length())).toString();
+    }
+
+    public static String replace(String str, char repl, String with)
+    {
+        int pos = str.indexOf(repl);
+
+        // If no replacement needed, return the original string
+        // and save StringBuffer allocation/char copying
+        if (pos < 0)
+        {
+            return str;
+        }
+
+        int          len       = str.length();
+        int          lendiff   = with.length() - 1;
+        StringBuffer out       =
+            new StringBuffer((lendiff <= 0) ? str.length()
+                : (str.length() + (10 * lendiff)));
+        int          lastindex = 0;
+        for (; pos >= 0; pos = str.indexOf(repl, lastindex = pos + 1))
+        {
+            out.append(substring(str, lastindex, pos)).append(with);
+        }
+
+        return out.append(substring(str, lastindex, len)).toString();
+    }
+
+    public static StringBuffer replace(
+        StringBuffer out, String s, String repl, String with)
+    {
+        int lastindex = 0;
+        int len = repl.length();
+        for (int index = s.indexOf(repl); index >= 0;
+                    index = s.indexOf(repl, lastindex = index + len))
+        {
+            // we have search string at position index
+            out.append(substring(s, lastindex, index)).append(with);
+        }
+
+        return out.append(substring(s, lastindex, len));
+    }
+
+    /**
+     * Split a string into an array of strings arround a character separator.
+     * This  function will be efficient for longer strings
+     *
+     * @param str the string to be split
+     * @param separator the separator character
+     *
+     * @return array of string subparts
+     */
+    public static String[] splitLongString(String str, char separator)
+    {
+        int len;
+        if (str == null || (len = str.length()) == 0)
+        {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+
+        int       oldPos = 0;
+        ArrayList list = new ArrayList();
+        for (
+            int pos = str.indexOf(separator); pos >= 0;
+                    pos = str.indexOf(separator, (oldPos = (pos + 1))))
+        {
+            list.add(substring(str, oldPos, pos));
+        }
+
+        list.add(substring(str, oldPos, len));
+
+        return (String[]) list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
+    }
+
+    /**
+     * Split a string into an array of strings arround a character separator.
+     * Each element can be optionally quoted by the quote character.<br>
+     * This function will be efficient for long strings
+     *
+     * @param str the string to be split
+     * @param separator the separator character
+     * @param quote the quote character
+     *
+     * @return array of string subparts
+     *
+     * @throws IllegalArgumentException DOCUMENT ME!
+     */
+    public static String[] splitLongString(
+        String str, char separator, char quote)
+    {
+        int len;
+        if (str == null || (len = str.length()) == 0)
+        {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+
+        int       oldPos = 0;
+        ArrayList list = new ArrayList();
+        for (int pos = 0; pos < len; oldPos = ++pos)
+        {
+            // Skip quoted text, if any
+            while ((pos < len) && (str.charAt(pos) == quote))
+            {
+                pos = str.indexOf(quote, pos + 1) + 1;
+
+                if (pos == 0)
+                {
+                    throw new IllegalArgumentException(
+                        "Closing quote missing in string '" + str + "'");
+                }
+            }
+
+            boolean quoted;
+
+            if (pos != oldPos)
+            {
+                quoted = true;
+
+                if ((pos < len) && (str.charAt(pos) != separator))
+                {
+                    throw new IllegalArgumentException(
+                        "Separator must follow closing quote in string '"
+                        + str + "'");
+                }
+            }
+            else
+            {
+                quoted     = false;
+                pos        = str.indexOf(separator, pos);
+                if (pos < 0)
+                {
+                    pos = len;
+                }
+            }
+
+            list.add(
+                quoted ? dequote(str, oldPos + 1, pos - 1, quote)
+                    : substring(str, oldPos, pos));
+        }
+
+        return (String[]) list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
+    }
+
+    /**
+     * Split a string into an array of strings arround a character separator.
+     * This  function will be efficient for short strings, for longer strings,
+     * another approach may be better
+     *
+     * @param str the string to be split
+     * @param separator the separator character
+     *
+     * @return array of string subparts
+     */
+    public static String[] splitShortString(String str, char separator)
+    {
+        int len;
+        if (str == null || (len = str.length()) == 0)
+        {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+
+        int lastTokenIndex = 0;
+
+        // Step 1: how many substrings?
+        //      We exchange double scan time for less memory allocation
+        for (int pos = str.indexOf(separator);
+            pos >= 0; pos = str.indexOf(separator, pos + 1))
+        {
+            lastTokenIndex++;
+        }
+
+        // Step 2: allocate exact size array
+        String[] list   = new String[lastTokenIndex + 1];
+
+        int      oldPos = 0;
+
+        // Step 3: retrieve substrings
+        for (
+            int pos = str.indexOf(separator), i = 0; pos >= 0;
+                    pos = str.indexOf(separator, (oldPos = (pos + 1))))
+        {
+            list[i++] = substring(str, oldPos, pos);
+        }
+
+        list[lastTokenIndex] = substring(str, oldPos, len);
+
+        return list;
+    }
+
+    /**
+     * Split a string into an array of strings arround a character separator.
+     * Each element can be optionally quoted by the quote character.<br>
+     * This function will be efficient for short strings, for longer strings,
+     * another approach may be better
+     *
+     * @param str the string to be split
+     * @param separator the separator character
+     * @param quote the quote character
+     *
+     * @return array of string subparts
+     *
+     * @throws IllegalArgumentException DOCUMENT ME!
+     */
+    public static String[] splitShortString(
+        String str, char separator, char quote)
+    {
+        int len;
+        if (str == null || (len = str.length()) == 0)
+        {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+
+        // Step 1: how many substrings?
+        //      We exchange double scan time for less memory allocation
+        int tokenCount = 0;
+        for (int pos = 0; pos < len; pos++)
+        {
+            tokenCount++;
+
+            int oldPos = pos;
+
+            // Skip quoted text, if any
+            while ((pos < len) && (str.charAt(pos) == quote))
+            {
+                pos = str.indexOf(quote, pos + 1) + 1;
+
+                // pos == 0 is not found (-1 returned by indexOf + 1)
+                if (pos == 0)
+                {
+                    throw new IllegalArgumentException(
+                        "Closing quote missing in string '" + str + "'");
+                }
+            }
+
+            if (pos != oldPos)
+            {
+                if ((pos < len) && (str.charAt(pos) != separator))
+                {
+                    throw new IllegalArgumentException(
+                        "Separator must follow closing quote in strng '"
+                        + str + "'");
+                }
+            }
+            else
+            {
+                pos = str.indexOf(separator, pos);
+                if (pos < 0)
+                {
+                    break;
+                }
+            }
+        }
+
+        // Main loop will finish one substring short when last char is separator
+        if (str.charAt(len - 1) == separator)
+        {
+            tokenCount++;
+        }
+
+        // Step 2: allocate exact size array
+        String[] list = new String[tokenCount];
+
+        // Step 3: retrieve substrings
+        // Note: on this pass we do not check for correctness,
+        //       since we have already done so
+        tokenCount--; // we want to stop one token short
+
+        int oldPos = 0;
+        for (int pos = 0, i = 0; i < tokenCount; i++, oldPos = ++pos)
+        {
+            boolean quoted;
+
+            // Skip quoted text, if any
+            while (str.charAt(pos) == quote)
+            {
+                pos = str.indexOf(quote, pos + 1) + 1;
+            }
+
+            if (pos != oldPos)
+            {
+                quoted = true;
+
+                if (str.charAt(pos) != separator)
+                {
+                    throw new IllegalArgumentException(
+                        "Separator must follow closing quote in strng '"
+                        + str + "'");
+                }
+            }
+            else
+            {
+                quoted     = false;
+                pos        = str.indexOf(separator, pos);
+            }
+
+            list[i] =
+                quoted ? dequote(str, oldPos + 1, pos - 1, quote)
+                    : substring(str, oldPos, pos);
+        }
+
+        list[tokenCount] = dequoteFull(str, oldPos, len, quote);
+
+        return list;
+    }
+
+    public static String substring(String str, int begin, int end)
+    {
+        if (begin == end)
+        {
+            return "";
+        }
+
+        return str.substring(begin, end);
+    }
+
+    public static String[] trim(String[] strings)
+    {
+        if (strings == null)
+        {
+            return null;
+        }
+
+        for (int i = 0, len = strings.length; i < len; i++)
+        {
+            strings[i] = strings[i].trim();
+        }
+
+        return strings;
+    }
+
+    /**
+     * Returns the minimum index >= 0, if any
+     *
+     * <p>
+     * Use to find the first of two characters in a string:<br>
+     * <code>minIndex(s.indexOf('/'), indexOf('\'))</code>
+     * </p>
+     *
+     */
+    public static int minIndex(int a, int b)
+    {
+        return (a < 0) ? b
+            : (b < 0) ? a
+                : (a < b) ? a : b;
+    }
+}