001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019/**
020 * Implements the CFML Function rand
021 */
022package lucee.runtime.functions.math;
023
024import java.security.NoSuchAlgorithmException;
025import java.security.SecureRandom;
026import java.util.Map;
027import java.util.Random;
028
029import lucee.commons.collection.HashMapPro;
030import lucee.runtime.PageContext;
031import lucee.runtime.crypt.CFMXCompat;
032import lucee.runtime.exp.ExpressionException;
033import lucee.runtime.ext.function.Function;
034
035public final class Rand implements Function {
036
037    private static Map<String, Random> randoms = new HashMapPro<String, Random>();
038
039        public static double call(PageContext pc ) throws ExpressionException {
040
041                return getRandom( CFMXCompat.ALGORITHM_NAME, Double.NaN ).nextDouble();
042        }
043
044        public static double call(PageContext pc, String algorithm) throws ExpressionException {
045
046        return getRandom( algorithm, Double.NaN ).nextDouble();
047        }
048
049    static synchronized Random getRandom(String algorithm, Double seed) throws ExpressionException {
050
051        algorithm = algorithm.toLowerCase();
052
053        Random result = randoms.get( algorithm );
054
055        if ( result == null || !seed.isNaN() ) {
056            if (CFMXCompat.ALGORITHM_NAME.equalsIgnoreCase( algorithm )) {
057
058                result = new Random();
059            }
060            else {
061
062                try {
063
064                    result = SecureRandom.getInstance( algorithm );
065                }
066                catch (NoSuchAlgorithmException e) {
067                    throw new ExpressionException("random algorithm ["+algorithm+"] is not installed on the system",e.getMessage());
068                }
069            }
070
071            if ( !seed.isNaN() )
072                result.setSeed( seed.longValue() );
073
074            randoms.put( algorithm, result );
075        }
076
077        return result;
078    }
079}