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 com.nimbusds.jose.util.Base64URL;
010
011import net.minidev.json.JSONAware;
012import net.minidev.json.JSONValue;
013
014
015/**
016 * The base class for representing identifiers and identities. Provides
017 * constructors that generate Base64URL-encoded secure random identifier
018 * values.
019 *
020 * <p>Extending classes must override the {@link #equals} method.
021 */
022public 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 = Base64URL.encode(n).toString();
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        @Override
132        public boolean equals(final Object o) {
133                if (this == o) return true;
134                if (o == null || getClass() != o.getClass()) return false;
135
136                Identifier that = (Identifier) o;
137
138                return getValue() != null ? getValue().equals(that.getValue()) : that.getValue() == null;
139
140        }
141
142
143        @Override
144        public int hashCode() {
145                return getValue() != null ? getValue().hashCode() : 0;
146        }
147}