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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @author Alexander V. Esin
23 package org.apache.harmony.security.x501;
25 import java.io.IOException;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Locale;
32 import javax.security.auth.x500.X500Principal;
33 import org.apache.harmony.security.asn1.ASN1SequenceOf;
34 import org.apache.harmony.security.asn1.ASN1SetOf;
35 import org.apache.harmony.security.asn1.BerInputStream;
36 import org.apache.harmony.security.asn1.DerInputStream;
37 import org.apache.harmony.security.x509.DNParser;
45 //ASN.1 DER encoding of Name
46 private volatile byte[] encoded;
49 private String rfc1779String;
52 private String rfc2253String;
55 private String canonicalString;
61 * Creates new <code>Name</code> instance from its DER encoding
63 * @param encoding - ASN.1 DER encoding
64 * @throws IOException - if encoding is wrong
66 public Name(byte[] encoding) throws IOException {
68 DerInputStream in = new DerInputStream(encoding);
70 if (in.getEndOffset() != encoding.length) {
71 throw new IOException("Wrong content length");
76 this.rdn = (List) in.content;
80 * Creates new <code>Name</code> instance
82 * @param name - Name as String
83 * @throws IOException - if string is wrong
85 public Name(String name) throws IOException {
86 rdn = new DNParser(name).parse();
89 // Creates Name instance
90 private Name(List rdn) {
95 * Returns <code>X500Principal</code> instance corresponding to this
96 * <code>Name</code> instance
98 * @return equivalent X500Principal object
100 public X500Principal getX500Principal(){
101 return new X500Principal(getName0(X500Principal.RFC2253));
105 * Returns Relative Distinguished Name as <code>String</code> according
106 * the format requested
109 * Name format requested
110 * @return Relative Distinguished Name as <code>String</code> according
111 * the format requested
113 public String getName(String format) {
116 // check X500Principal constants first
118 if (X500Principal.RFC1779.equals(format)) {
120 if (rfc1779String == null) {
121 rfc1779String = getName0(format);
123 return rfc1779String;
125 } else if (X500Principal.RFC2253.equals(format)) {
127 if (rfc2253String == null) {
128 rfc2253String = getName0(format);
130 return rfc2253String;
132 } else if (X500Principal.CANONICAL.equals(format)) {
134 if (canonicalString == null) {
135 canonicalString = getName0(format);
137 return canonicalString;
141 // compare ignore case
143 else if (X500Principal.RFC1779.equalsIgnoreCase(format)) {
145 if (rfc1779String == null) {
146 rfc1779String = getName0(X500Principal.RFC1779);
148 return rfc1779String;
150 } else if (X500Principal.RFC2253.equalsIgnoreCase(format)) {
152 if (rfc2253String == null) {
153 rfc2253String = getName0(X500Principal.RFC2253);
155 return rfc2253String;
157 } else if (X500Principal.CANONICAL.equalsIgnoreCase(format)) {
159 if (canonicalString == null) {
160 canonicalString = getName0(X500Principal.CANONICAL);
162 return canonicalString;
165 throw new IllegalArgumentException("Illegal format: " + format);
170 * Returns Relative Distinguished Name as <code>String</code> according
171 * the format requested, format is int value
174 * Name format requested
175 * @return Relative Distinguished Name as <code>String</code> according
176 * the format requested
178 private String getName0(String format) {
180 StringBuffer name = new StringBuffer();
182 // starting with the last element and moving to the first.
183 for (int i = rdn.size() - 1; i >= 0; i--) {
184 List atavList = (List) rdn.get(i);
186 if (X500Principal.CANONICAL == format) {
187 List sortedList = new LinkedList(atavList);
188 Collections.sort(sortedList,
189 new AttributeTypeAndValueComparator());
190 atavList = sortedList;
193 // Relative Distinguished Name to string
194 Iterator it = atavList.iterator();
195 while (it.hasNext()) {
196 AttributeTypeAndValue _ava = (AttributeTypeAndValue) it.next();
197 _ava.appendName(format, name);
200 if (X500Principal.RFC1779 == format) {
210 if (format == X500Principal.RFC1779) {
216 String sName = name.toString();
217 if (X500Principal.CANONICAL.equals(format)) {
218 sName = sName.toLowerCase(Locale.US);
224 * Gets encoded form of DN
226 * @return return encoding, no copying is performed
228 public byte[] getEncoded() {
229 if (encoded == null) {
230 encoded = ASN1.encode(this);
236 * According to RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt)
237 * X.501 Name structure is defined as follows:
242 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
244 * RelativeDistinguishedName ::=
245 * SET OF AttributeTypeAndValue
249 public static final ASN1SetOf ASN1_RDN = new ASN1SetOf(
250 AttributeTypeAndValue.ASN1);
252 public static final ASN1SequenceOf ASN1 = new ASN1SequenceOf(ASN1_RDN) {
254 public Object getDecodedObject(BerInputStream in) {
255 return new Name((List) in.content);
258 public Collection getValues(Object object) {
259 return ((Name) object).rdn; //FIXME what about get method?