1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17/**
18* @author Alexander V. Esin, Stepan M. Mishura
19* @version $Revision$
20*/
21
22package org.apache.harmony.security.utils;
23
24import java.util.Arrays;
25
26/**
27 * Instance of this class represents ObjectIdentifier (OID).
28 *
29 * OID is represented as a sequence of subidentifier.
30 * Each subidentifier is represented as non negative integer value.
31 * There are at least 2 subidentifiers in the sequence.
32 *
33 * Valid values for first subidentifier are 0, 1 and 2.
34 * If the first subidentifier has 0 or 1 value the second
35 * subidentifier MUST be less then 40.
36 *
37 * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
38 */
39
40public final class ObjectIdentifier {
41
42    //OID as array of integers
43    private final int[] oid;
44
45    //hash code
46    private int hash = -1;
47
48    //OID as string
49    private String soid;
50
51    // stores the following: "OID." + soid
52    private String sOID;
53
54    // OID alias name
55    private String name;
56
57    // OID's group
58    private Object group;
59
60    /**
61     * Creates ObjectIdentifier(OID) from array of integers.
62     *
63     * @param oid - array of integers
64     * @return - OID object
65     * @throws NullPointerException     - if oid is null
66     * @throws IllegalArgumentException - if oid is invalid
67     */
68    public ObjectIdentifier(int[] oid) {
69
70        validateOid(oid);
71
72        this.oid = oid;
73    }
74
75    /**
76     * Creates ObjectIdentifier(OID) from array of integers.
77     *
78     * @param oid - array of integers
79     * @param name - name of OID
80     * @param oidGroup - OID's group. Is used to separate different OID's
81     * @return - OID object
82     * @throws NullPointerException     - if oid is null
83     * @throws IllegalArgumentException - if oid is invalid
84     */
85    public ObjectIdentifier(int[] oid, String name, Object oidGroup) {
86        this(oid);
87
88        if (oidGroup == null) {
89            throw new NullPointerException("oidGroup == null");
90        }
91        this.group = oidGroup;
92
93        this.name = name;
94        toOIDString(); // init soid & sOID
95    }
96
97    /**
98     * Gets OID.
99     *
100     * @return oid
101     */
102    public int[] getOid() {
103        return oid;
104    }
105
106    /**
107     * Gets OID's name.
108     *
109     * @return name
110     */
111    public String getName() {
112        return name;
113    }
114
115    /**
116     * Gets OID's group.
117     *
118     * @return group
119     */
120    public Object getGroup() {
121        return group;
122    }
123
124    /**
125     * Compares object with OID for equality.
126     *
127     * @return true if object is ObjectIdentifier and it has the same
128     *         representation as array of integers, otherwise false
129     */
130    public boolean equals(Object o) {
131        if (this == o) {
132            return true;
133        }
134        if (o == null || this.getClass() != o.getClass()) {
135            return false;
136        }
137        return Arrays.equals(oid, ((ObjectIdentifier) o).oid);
138    }
139
140    /**
141     * Add "OID." to the beginning of string representation.
142     *
143     * @return oid as string
144     */
145    public String toOIDString() {
146        if (sOID == null) {
147            sOID = "OID." + toString();
148        }
149        return sOID;
150    }
151
152    /**
153     * Overrides Object.toString()
154     *
155     * @return oid as string
156     */
157    public String toString() {
158        if (soid == null) {
159            StringBuilder sb = new StringBuilder(4 * oid.length);
160
161            for (int i = 0; i < oid.length - 1; ++i) {
162                sb.append(oid[i]);
163                sb.append('.');
164            }
165            sb.append(oid[oid.length - 1]);
166            soid = sb.toString();
167        }
168        return soid;
169    }
170
171    /**
172     * @see java.lang.Object#hashCode()
173     */
174    public int hashCode() {
175        if (hash == -1) {
176            hash = hashIntArray(oid);
177        }
178        return hash;
179    }
180
181    /**
182     * Validates ObjectIdentifier (OID).
183     *
184     * @param oid - oid as array of integers
185     * @throws NullPointerException     - if oid is null
186     * @throws IllegalArgumentException - if oid is invalid
187     */
188    public static void validateOid(int[] oid) {
189
190        if (oid == null) {
191            throw new NullPointerException("oid == null");
192        }
193
194        if (oid.length < 2) {
195            throw new IllegalArgumentException("OID MUST have at least 2 subidentifiers");
196        }
197
198        if (oid[0] > 2) {
199            throw new IllegalArgumentException("Valid values for first subidentifier are 0, 1 and 2");
200        } else if (oid[0] != 2 && oid[1] > 39) {
201            throw new IllegalArgumentException("If the first subidentifier has 0 or 1 value the second subidentifier value MUST be less than 40");
202        }
203    }
204
205    /**
206     * Returns hash code for array of integers
207     *
208     * @param oid - array of integers
209     */
210    public static int hashIntArray(int[] array) {
211        int intHash = 0;
212        for (int i = 0; i < array.length && i < 4; i++) {
213            intHash += array[i] << (8 * i); //TODO what about to find better one?
214        }
215        return intHash & 0x7FFFFFFF; // only positive
216    }
217}
218