/* See LICENSE for licensing and NOTICE for copyright. */
package org.cryptacular.x509.dn;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* Simple implementation of the X.501 RDNSequence type described in section 4.1.2.4 of RFC 2459.
*
* @author Middleware Services
*/
public class RDNSequence implements Iterable<RDN>
{
/** Maintains the list/sequence of RDNs. */
private final List<RDN> rdns = new ArrayList<>(10);
/**
* Adds an RDN to the sequence.
*
* @param rdn RDN to add.
*/
public void add(final RDN rdn)
{
rdns.add(rdn);
}
@Override
public Iterator<RDN> iterator()
{
return rdns.iterator();
}
/** @return Iterable that moves backward over the RDN sequence. */
public Iterable<RDN> backward()
{
return
() -> new Iterator<RDN>() {
/** List iterator. */
private final ListIterator<RDN> it = rdns.listIterator(rdns.size());
@Override
public boolean hasNext()
{
return it.hasPrevious();
}
@Override
public RDN next()
{
return it.previous();
}
@Override
public void remove()
{
throw new UnsupportedOperationException("Remove not supported");
}
};
}
/**
* Gets an immutable list of all attributes of the given type. The order of the returned list reflects the ordering of
* the RDNs and their attributes.
*
* @param type Attribute type.
*
* @return Non-null list of attributes of given type. An empty list is returned if there are no attributes of the
* given type.
*/
public List<String> getValues(final AttributeType type)
{
final List<String> values = new ArrayList<>(rdns.size());
for (RDN rdn : rdns) {
values.addAll(rdn.getAttributes().getValues(type));
}
return Collections.unmodifiableList(values);
}
/**
* Gets the first value of the given type that appears in the attribute list of any RDN in the sequence.
*
* @param type Attribute type.
*
* @return Value of first attribute of given type or null if no attributes of given type exist.
*/
public String getValue(final AttributeType type)
{
final List<String> values = getValues(type);
if (values.size() > 0) {
return values.get(0);
}
return null;
}
/**
* Creates a comma-separated list of TYPE=VALUE tokens from the attributes in the list in order.
*
* @return String representation that resembles an X.509 distinguished name, e.g. <code>CN=foo, OU=Bar, dc=example,
* dc=com</code>.
*/
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder();
int i = 0;
for (RDN rdn : this) {
for (Attribute attr : rdn.getAttributes()) {
if (i++ > 0) {
builder.append(", ");
}
builder.append(attr.getType()).append('=').append(attr.getValue());
}
}
return builder.toString();
}
}