    001    package org.apache.turbine.util;
    002
    003
    004    /*
    005     * Licensed to the Apache Software Foundation (ASF) under one
    006     * or more contributor license agreements.  See the NOTICE file
    007     * distributed with this work for additional information
    008     * regarding copyright ownership.  The ASF licenses this file
    009     * to you under the Apache License, Version 2.0 (the
    010     * "License"); you may not use this file except in compliance
    011     * with the License.  You may obtain a copy of the License at
    012     *
    013     *   http://www.apache.org/licenses/LICENSE-2.0
    014     *
    015     * Unless required by applicable law or agreed to in writing,
    016     * software distributed under the License is distributed on an
    017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    018     * KIND, either express or implied.  See the License for the
    019     * specific language governing permissions and limitations
    020     * under the License.
    021     */
    022
    023
    024    import java.util.Random;
    025
    026    /**
    027     * This class generates a unique 10+ character id.  This is good for
    028     * authenticating users or tracking users around.
    029     *
    030     * <p>This code was borrowed from Apache
    031     * JServ.JServServletManager.java.  It is what Apache JServ uses to
    032     * generate session ids for users.  Unfortunately, it was not included
    033     * in Apache JServ as a class, so I had to create one here in order to
    034     * use it.
    035     *
    036     * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
    037     * @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
    038     * @version $Id: GenerateUniqueId.java 615328 2008-01-25 20:25:05Z tv $
    039     */
    040    public class GenerateUniqueId
    041    {
    042        /*
    043         * Create a suitable string for session identification.  Use
    044         * synchronized count and time to ensure uniqueness.  Use random
    045         * string to ensure the timestamp cannot be guessed by programmed
    046         * attack.
    047         *
    048         * Format of id is <6 chars random><3 chars time><1+ char count>
    049         */
    050        static private int session_count = 0;
    051        static private long lastTimeVal = 0;
    052        static private Random randomSource = new java.util.Random();
    053
    054        // MAX_RADIX is 36
    055
    056        /*
    057         * We want to have a random string with a length of 6 characters.
    058         * Since we encode it BASE 36, we've to modulo it with the
    059         * following value:
    060         */
    061        public final static long maxRandomLen = 2176782336L; // 36 ** 6
    062
    063        /*
    064         * The session identifier must be unique within the typical
    065         * lifespan of a Session; the value can roll over after that.  3
    066         * characters: (this means a roll over after over a day, which is
    067         * much larger than a typical lifespan)
    068         */
    069        public final static long maxSessionLifespanTics = 46656; // 36 ** 3
    070
    071        /*
    072         * Millisecons between different tics.  So this means that the
    073         * 3-character time string has a new value every 2 seconds:
    074         */
    075        public final static long ticDifference = 2000;
    076
    077        /**
    078         * Get the unique id.
    079         *
    080         * <p>NOTE: This must work together with
    081         * get_jserv_session_balance() in jserv_balance.c
    082         *
    083         * @return A String with the new unique id.
    084         */
    085        static synchronized public String getIdentifier()
    086        {
    087            StringBuffer sessionId = new StringBuffer();
    088
    089            // Random value.
    090            long n = randomSource.nextLong();
    091            if (n < 0) n = -n;
    092            n %= maxRandomLen;
    093
    094            // Add maxLen to pad the leading characters with '0'; remove
    095            // first digit with substring.
    096            n += maxRandomLen;
    097            sessionId.append(Long.toString(n, Character.MAX_RADIX)
    098                    .substring(1));
    099
    100            long timeVal = (System.currentTimeMillis() / ticDifference);
    101
    102            // Cut.
    103            timeVal %= maxSessionLifespanTics;
    104
    105            // Padding, see above.
    106            timeVal += maxSessionLifespanTics;
    107
    108            sessionId.append(Long.toString(timeVal, Character.MAX_RADIX)
    109                    .substring(1));
    110
    111            /*
    112             * Make the string unique: append the session count since last
    113             * time flip.
    114             */
    115
    116            // Count sessions only within tics.  So the 'real' session
    117            // count isn't exposed to the public.
    118            if (lastTimeVal != timeVal)
    119            {
    120                lastTimeVal = timeVal;
    121                session_count = 0;
    122            }
    123            sessionId.append(Long.toString(++session_count,
    124                    Character.MAX_RADIX));
    125
    126            return sessionId.toString();
    127        }
    128
    129        /**
    130         * Get the unique id.
    131         *
    132         * @param jsIdent A String.
    133         * @return A String with the new unique id.
    134         */
    135        synchronized public String getIdentifier(String jsIdent)
    136        {
    137            if (jsIdent != null && jsIdent.length() > 0)
    138            {
    139                return getIdentifier() + "." + jsIdent;
    140            }
    141            return getIdentifier();
    142        }
    143
    144        /**
    145         * Simple test of the functionality.
    146         *
    147         * @param args A String[] with the command line arguments.
    148         */
    149        public static void main(String[] args)
    150        {
    151            System.out.println(GenerateUniqueId.getIdentifier());
    152            System.out.println(GenerateUniqueId.getIdentifier());
    153            System.out.println(GenerateUniqueId.getIdentifier());
    154            System.out.println(GenerateUniqueId.getIdentifier());
    155        }
    156    }