alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (TokenTracker.java)

This example Java source code file (TokenTracker.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

entry, linkedlist, max_intervals, messageprop, string, stringbuffer, tokentracker, util

The TokenTracker.java Java example source code

/*
 * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.jgss;

import org.ietf.jgss.MessageProp;
import java.util.LinkedList;

/**
 * A utility class that implements a number list that keeps track of which
 * tokens have arrived by storing their token numbers in the list. It helps
 * detect old tokens, out of sequence tokens, and duplicate tokens.
 *
 * Each element of the list is an interval [a, b]. Its existence in the
 * list implies that all token numbers in the range a, a+1, ..., b-1, b
 * have arrived. Gaps in arrived token numbers are represented by the
 * numbers that fall in between two elements of the list. eg. {[a,b],
 * [c,d]} indicates that the token numbers b+1, ..., c-1 have not arrived
 * yet.
 *
 * The maximum number of intervals that we keep track of is
 * MAX_INTERVALS. Thus if there are too many gaps, then some of the older
 * sequence numbers are deleted from the list. The earliest sequence number
 * that exists in the list is the windowStart. The next expected sequence
 * number, or expectedNumber, is one greater than the latest sequence
 * number in the list.
 *
 * The list keeps track the first token number that should have arrived
 * (initNumber) so that it is able to detect if certain numbers occur after
 * the first valid token number but before windowStart. That would happen
 * if the number of elements (intervals) exceeds MAX_INTERVALS and some
 * initial elements had  to be deleted.
 *
 * The working of the list is optimized for the normal case where the
 * tokens arrive in sequence.
 *
 * @author Mayank Upadhyay
 * @since 1.4
 */
public class TokenTracker {

    static final int MAX_INTERVALS = 5;

    private int initNumber;
    private int windowStart;
    private int expectedNumber;

    private int windowStartIndex = 0;

    private LinkedList<Entry> list = new LinkedList();

    public TokenTracker(int initNumber) {

        this.initNumber = initNumber;
        this.windowStart = initNumber;
        this.expectedNumber = initNumber;

        // Make an entry with one less than the expected first token
        Entry entry = new Entry(initNumber-1);

        list.add(entry);
    }

    /**
     * Returns the index for the entry into which this number will fit. If
     * there is none, it returns the index of the last interval
     * which precedes this number. It returns -1 if the number needs to be
     * a in a new interval ahead of the whole list.
     */
    private int getIntervalIndex(int number) {
        Entry entry = null;
        int i;
        // Start from the rear to optimize for the normal case
        for (i = list.size() - 1; i >= 0; i--) {
            entry = list.get(i);
            if (entry.compareTo(number) <= 0)
                break;
        }
        return i;
    }

    /**
     * Sets the sequencing and replay information for the given token
     * number.
     *
     * The following represents the number line with positions of
     * initNumber, windowStart, expectedNumber marked on it. Regions in
     * between them show the different sequencing and replay state
     * possibilites for tokens that fall in there.
     *
     *  (1)      windowStart
     *           initNumber               expectedNumber
     *              |                           |
     *           ---|---------------------------|---
     *          GAP |    DUP/UNSEQ              | GAP
     *
     *
     *  (2)       initNumber   windowStart   expectedNumber
     *              |               |              |
     *           ---|---------------|--------------|---
     *          GAP |      OLD      |  DUP/UNSEQ   | GAP
     *
     *
     *  (3)                                windowStart
     *           expectedNumber            initNumber
     *              |                           |
     *           ---|---------------------------|---
     *    DUP/UNSEQ |           GAP             | DUP/UNSEQ
     *
     *
     *  (4)      expectedNumber    initNumber   windowStart
     *              |               |              |
     *           ---|---------------|--------------|---
     *    DUP/UNSEQ |        GAP    |    OLD       | DUP/UNSEQ
     *
     *
     *
     *  (5)      windowStart   expectedNumber    initNumber
     *              |               |              |
     *           ---|---------------|--------------|---
     *          OLD |    DUP/UNSEQ  |     GAP      | OLD
     *
     *
     *
     * (This analysis leaves out the possibility that expectedNumber passes
     * initNumber after wrapping around. That may be added later.)
     */
    synchronized public final void getProps(int number, MessageProp prop) {

        boolean gap = false;
        boolean old = false;
        boolean unsequenced = false;
        boolean duplicate = false;

        // System.out.println("\n\n==========");
        // System.out.println("TokenTracker.getProps(): number=" + number);
        // System.out.println(toString());

        int pos = getIntervalIndex(number);
        Entry entry = null;
        if (pos != -1)
            entry = list.get(pos);

        // Optimize for the expected case:

        if (number == expectedNumber) {
            expectedNumber++;
        } else {

            // Next trivial case is to check for duplicate
            if (entry != null && entry.contains(number))
                duplicate = true;
            else {

                if (expectedNumber >= initNumber) {

                    // Cases (1) and (2)

                    if (number > expectedNumber) {
                        gap = true;
                    } else if (number >= windowStart) {
                        unsequenced = true;
                    } else if (number >= initNumber) {
                        old = true;
                    } else {
                        gap = true;
                    }
                } else {

                    // Cases (3), (4) and (5)

                    if (number > expectedNumber) {
                        if (number < initNumber) {
                            gap = true;
                        } else if (windowStart >= initNumber) {
                            if (number >= windowStart) {
                               unsequenced = true;
                            } else
                                old = true;
                        } else {
                            old = true;
                        }
                    } else if (windowStart > expectedNumber) {
                        unsequenced = true;
                    } else if (number < windowStart) {
                        old = true;
                    } else
                        unsequenced = true;
                }
            }
        }

        if (!duplicate && !old)
            add(number, pos);

        if (gap)
            expectedNumber = number+1;

        prop.setSupplementaryStates(duplicate, old, unsequenced, gap,
                                    0, null);

        // System.out.println("Leaving with state:");
        // System.out.println(toString());
        // System.out.println("==========\n");
    }

    /**
     * Adds the number to the list just after the entry that is currently
     * at position prevEntryPos. If prevEntryPos is -1, then the number
     * will begin a new interval at the front of the list.
     */
    private void add(int number, int prevEntryPos) {

        Entry entry;
        Entry entryBefore = null;
        Entry entryAfter = null;

        boolean appended = false;
        boolean prepended = false;

        if (prevEntryPos != -1) {
            entryBefore = list.get(prevEntryPos);

            // Can this number simply be added to the previous interval?
            if (number == (entryBefore.getEnd() + 1)) {
                entryBefore.setEnd(number);
                appended = true;
            }
        }

        // Now check the interval that follows this number

        int nextEntryPos = prevEntryPos + 1;
        if ((nextEntryPos) < list.size()) {
            entryAfter = list.get(nextEntryPos);

            // Can this number simply be added to the next interval?
            if (number == (entryAfter.getStart() - 1)) {
                if (!appended) {
                    entryAfter.setStart(number);
                } else {
                    // Merge the two entries
                    entryAfter.setStart(entryBefore.getStart());
                    list.remove(prevEntryPos);
                    // Index of any entry following this gets decremented
                    if (windowStartIndex > prevEntryPos)
                        windowStartIndex--;
                }
                prepended = true;
            }
        }

        if (prepended || appended)
            return;

        /*
         * At this point we know that the number will start a new interval
         * which needs to be added to the list. We might have to recyle an
         * older entry in the list.
         */

        if (list.size() < MAX_INTERVALS) {
            entry = new Entry(number);
            if (prevEntryPos  < windowStartIndex)
                windowStartIndex++; // due to the insertion which will happen
        } else {
            /*
             * Delete the entry that marks the start of the current window.
             * The marker will automatically point to the next entry in the
             * list when this happens. If the current entry is at the end
             * of the list then set the marker to the start of the list.
             */
            int oldWindowStartIndex = windowStartIndex;
            if (windowStartIndex == (list.size() - 1))
                windowStartIndex = 0;

            entry = list.remove(oldWindowStartIndex);
            windowStart = list.get(windowStartIndex).getStart();
            entry.setStart(number);
            entry.setEnd(number);

            if (prevEntryPos >= oldWindowStartIndex) {
                prevEntryPos--; // due to the deletion that just happened
            } else {
                /*
                 * If the start of the current window just moved from the
                 * end of the list to the front of the list, and if the new
                 * entry will be added to the front of the list, then
                 * the new entry is the actual window start.
                 * eg, Consider { [-10, -8], ..., [-6, -3], [3, 9]}. In
                 * this list, suppose the element [3, 9] is the start of
                 * the window and has to be deleted to make place to add
                 * [-12, -12]. The resultant list will be
                 * {[-12, -12], [-10, -8], ..., [-6, -3]} and the new start
                 * of the window should be the element [-12, -12], not
                 * [-10, -8] which succeeded [3, 9] in the old list.
                 */
                if (oldWindowStartIndex != windowStartIndex) {
                    // windowStartIndex is 0 at this point
                    if (prevEntryPos == -1)
                        // The new entry is going to the front
                        windowStart = number;
                } else {
                    // due to the insertion which will happen:
                    windowStartIndex++;
                }
            }
        }

        // Finally we are ready to actually add to the list at index
        // 'prevEntryPos+1'

        list.add(prevEntryPos+1, entry);
    }

    public String toString() {
        StringBuffer buf = new StringBuffer("TokenTracker: ");
        buf.append(" initNumber=").append(initNumber);
        buf.append(" windowStart=").append(windowStart);
        buf.append(" expectedNumber=").append(expectedNumber);
        buf.append(" windowStartIndex=").append(windowStartIndex);
        buf.append("\n\tIntervals are: {");
        for (int i = 0; i < list.size(); i++) {
            if (i != 0)
                buf.append(", ");
            buf.append(list.get(i).toString());
        }
        buf.append('}');
        return buf.toString();
    }

    /**
     * An entry in the list that represents the sequence of received
     * tokens. Each entry is actaully an interval of numbers, all of which
     * have been received.
     */
    class Entry {

        private int start;
        private int end;

        Entry(int number) {
            start = number;
            end = number;
        }

        /**
         * Returns -1 if this interval represented by this entry precedes
         * the number, 0 if the the number is contained in the interval,
         * and -1 if the interval occurs after the number.
         */
        final int compareTo(int number) {
            if (start > number)
                return 1;
            else if (end < number)
                return -1;
            else
                return 0;
        }

        final boolean contains(int number) {
            return (number >= start &&
                    number <= end);
        }

        final void append(int number) {
            if (number == (end + 1))
                end = number;
        }

        final void setInterval(int start, int end) {
            this.start = start;
            this.end = end;
        }

        final void setEnd(int end) {
            this.end = end;
        }

        final void setStart(int start) {
            this.start = start;
        }

        final int getStart() {
            return start;
        }

        final int getEnd() {
            return end;
        }

        public String toString() {
            return ("[" + start + ", " + end + "]");
        }

    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java TokenTracker.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.