001/*
002 *  Copyright 2012 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.util;
017
018import java.io.UnsupportedEncodingException;
019import java.security.MessageDigest;
020import java.security.NoSuchAlgorithmException;
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.StringTokenizer;
024
025import org.apache.commons.codec.binary.Base64;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * A collection of String management utility methods.
031 */
032public final class StringUtils
033{
034    private static final Logger __LOGGER = LoggerFactory.getLogger(StringUtils.class);
035    
036    private StringUtils()
037    {
038        // empty private constructor
039    }
040    
041    /**
042     * Extract String values from a comma seprated list.
043     * @param values the comma separated list
044     * @return a collection of String or an empty collection if string is null or empty.
045     */
046    public static Collection<String> stringToCollection(String values)
047    {
048        Collection<String> result = new ArrayList<>();
049        if ((values != null) && (values.length() > 0))
050        {
051            // Explore the string list with a stringtokenizer with ','.
052            StringTokenizer stk = new StringTokenizer(values, ",");
053
054            while (stk.hasMoreTokens())
055            {
056                // Don't forget to trim
057                result.add(stk.nextToken().trim());
058            }
059        }
060
061        return result;
062    }
063
064    /**
065     * Extract String values from a comma seprated list.
066     * @param values the comma separated list
067     * @return an array of String
068     */
069    public static String[] stringToStringArray(String values)
070    {
071        Collection<String> coll = stringToCollection(values);
072        return coll.toArray(new String[coll.size()]);
073    }
074    
075    /**
076     * Generates a unique String key, based on System.currentTimeMillis()
077     * @return a unique String value
078     */
079    public static String generateKey()
080    {
081        long value;
082        
083        // Find a new value
084        synchronized (StringUtils.class)
085        {
086            value = System.currentTimeMillis();
087
088            try
089            {
090                Thread.sleep(15);
091            }
092            catch (InterruptedException e)
093            {
094                // does nothing, continue
095            }
096        }
097
098        // Convert it to a string using radix 36 (more compact)
099        String longString = Long.toString(value, Character.MAX_RADIX);
100    
101        return longString;
102    }
103    
104    /**
105     * Encrypt a password by using first MD5 Hash and base64 encoding.
106     * @param password The password to be encrypted.
107     * @return The password encrypted or null if the MD5 is not supported
108     */
109    public static String md5Base64(String password)
110    {
111        if (password == null)
112        {
113            return null;
114        }
115        
116        MessageDigest md5;
117        try
118        {
119            md5 = MessageDigest.getInstance("MD5");
120        }
121        catch (NoSuchAlgorithmException e)
122        {
123            // This error exception not be raised since MD5 is embedded in the JDK
124            __LOGGER.error("Cannot encode the password to md5Base64", e);
125            return null;
126        }
127        
128        // MD5-hash the password.
129        md5.reset();
130        try
131        {
132            md5.update(password.getBytes("UTF-8"));
133        }
134        catch (UnsupportedEncodingException e)
135        {
136            throw new IllegalStateException(e);
137        }
138        byte [] hash = md5.digest();
139        
140        // Base64-encode the result.
141        try
142        {
143            return new String(Base64.encodeBase64(hash), "UTF-8");
144        }
145        catch (UnsupportedEncodingException e)
146        {
147            throw new IllegalStateException(e);
148        }
149    }
150    
151    /**
152     * Encode an url using UTF-8 encoding, except that spaces are encoded using %20
153     * @param url The url to encode
154     * @return The url encoded
155     */
156    public static String encode(String url)
157    {
158        try
159        {
160            String encodedUrl = java.net.URLEncoder.encode(url, "UTF-8"); 
161            return encodedUrl.replaceAll("\\+", "%20");
162        }
163        catch (UnsupportedEncodingException e)
164        {
165            return url;
166        }
167    }
168}