001package com.nimbusds.oauth2.sdk.id;
002
003
004import java.io.Serializable;
005import java.security.SecureRandom;
006
007import org.apache.commons.lang3.StringUtils;
008
009import org.apache.commons.codec.binary.Base64;
010
011import net.minidev.json.JSONAware;
012import net.minidev.json.JSONValue;
013
014
015/**
016 * The base abstract class for representing identifiers and identities. 
017 * Provides constructors that generate Base64URL-encoded secure random 
018 * identifier values.
019 *
020 * <p>Extending classes must override the {@link #equals} method.
021 */
022public abstract class Identifier implements Serializable, Comparable<Identifier>, JSONAware {
023        
024        
025        /**
026         * The default byte length of generated identifiers.
027         */
028        public static final int DEFAULT_BYTE_LENGTH = 32;
029        
030        
031        /**
032         * The secure random generator.
033         */
034        private static final SecureRandom secureRandom = new SecureRandom();
035
036
037        /**
038         * The identifier value.
039         */
040        private final String value;
041
042
043        /**
044         * Creates a new identifier with the specified value.
045         *
046         * @param value The identifier value. Must not be {@code null} or empty
047         *              string.
048         */
049        public Identifier(final String value) {
050
051                if (StringUtils.isBlank(value))
052                        throw new IllegalArgumentException("The value must not be null or empty string");
053
054                this.value = value;
055        }
056
057
058        /**
059         * Creates a new identifier with a randomly generated value of the 
060         * specified byte length, Base64URL-encoded.
061         *
062         * @param byteLength The byte length of the value to generate. Must be
063         *                   greater than one.
064         */
065        public Identifier(final int byteLength) {
066                
067                if (byteLength < 1)
068                        throw new IllegalArgumentException("The byte length must be a positive integer");
069                
070                byte[] n = new byte[byteLength];
071                
072                secureRandom.nextBytes(n);
073
074                value = Base64.encodeBase64URLSafeString(n);
075        }
076        
077        
078        /**
079         * Creates a new identifier with a randomly generated 256-bit 
080         * (32-byte) value, Base64URL-encoded.
081         */
082        public Identifier() {
083
084                this(DEFAULT_BYTE_LENGTH);
085        }
086
087
088        /**
089         * Returns the value of this identifier.
090         *
091         * @return The value.
092         */
093        public String getValue() {
094
095                return value;
096        }
097
098
099        /**
100         * Returns the JSON string representation of this identifier.
101         *
102         * @return The JSON string.
103         */
104        @Override
105        public String toJSONString() {
106
107                StringBuilder sb = new StringBuilder("\"");
108                sb.append(JSONValue.escape(value));
109                sb.append('"');
110                return sb.toString();
111        }
112        
113        
114        /**
115         * @see #getValue
116         */
117        @Override
118        public String toString() {
119        
120                return getValue();
121        }
122
123
124        @Override
125        public int compareTo(final Identifier other) {
126
127                return getValue().compareTo(other.getValue());
128        }
129
130
131        /**
132         * Overrides {@code Object.hashCode()}.
133         *
134         * @return The object hash code.
135         */
136        @Override
137        public int hashCode() {
138        
139                return value.hashCode();
140        }
141        
142        
143        /**
144         * Overrides {@code Object.equals()}.
145         *
146         * @param object The object to compare to.
147         *
148         * @return {@code true} if the objects have the same value, otherwise
149         *         {@code false}.
150         */
151        @Override
152        public abstract boolean equals(final Object object);
153}