Home | History | Annotate | Download | only in DNS
      1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) xbill.org)
      2 
      3 package org.xbill.DNS;
      4 
      5 import java.io.Serializable;
      6 import java.util.*;
      7 
      8 /**
      9  * A set of Records with the same name, type, and class.  Also included
     10  * are all RRSIG records signing the data records.
     11  * @see Record
     12  * @see RRSIGRecord
     13  *
     14  * @author Brian Wellington
     15  */
     16 
     17 public class RRset implements Serializable {
     18 
     19 private static final long serialVersionUID = -3270249290171239695L;
     20 
     21 /*
     22  * rrs contains both normal and RRSIG records, with the RRSIG records
     23  * at the end.
     24  */
     25 private List rrs;
     26 private short nsigs;
     27 private short position;
     28 
     29 /** Creates an empty RRset */
     30 public
     31 RRset() {
     32 	rrs = new ArrayList(1);
     33 	nsigs = 0;
     34 	position = 0;
     35 }
     36 
     37 /** Creates an RRset and sets its contents to the specified record */
     38 public
     39 RRset(Record record) {
     40 	this();
     41 	safeAddRR(record);
     42 }
     43 
     44 /** Creates an RRset with the contents of an existing RRset */
     45 public
     46 RRset(RRset rrset) {
     47 	synchronized (rrset) {
     48 		rrs = (List) ((ArrayList)rrset.rrs).clone();
     49 		nsigs = rrset.nsigs;
     50 		position = rrset.position;
     51 	}
     52 }
     53 
     54 private void
     55 safeAddRR(Record r) {
     56 	if (!(r instanceof RRSIGRecord)) {
     57 		if (nsigs == 0)
     58 			rrs.add(r);
     59 		else
     60 			rrs.add(rrs.size() - nsigs, r);
     61 	} else {
     62 		rrs.add(r);
     63 		nsigs++;
     64 	}
     65 }
     66 
     67 /** Adds a Record to an RRset */
     68 public synchronized void
     69 addRR(Record r) {
     70 	if (rrs.size() == 0) {
     71 		safeAddRR(r);
     72 		return;
     73 	}
     74 	Record first = first();
     75 	if (!r.sameRRset(first))
     76 		throw new IllegalArgumentException("record does not match " +
     77 						   "rrset");
     78 
     79 	if (r.getTTL() != first.getTTL()) {
     80 		if (r.getTTL() > first.getTTL()) {
     81 			r = r.cloneRecord();
     82 			r.setTTL(first.getTTL());
     83 		} else {
     84 			for (int i = 0; i < rrs.size(); i++) {
     85 				Record tmp = (Record) rrs.get(i);
     86 				tmp = tmp.cloneRecord();
     87 				tmp.setTTL(r.getTTL());
     88 				rrs.set(i, tmp);
     89 			}
     90 		}
     91 	}
     92 
     93 	if (!rrs.contains(r))
     94 		safeAddRR(r);
     95 }
     96 
     97 /** Deletes a Record from an RRset */
     98 public synchronized void
     99 deleteRR(Record r) {
    100 	if (rrs.remove(r) && (r instanceof RRSIGRecord))
    101 		nsigs--;
    102 }
    103 
    104 /** Deletes all Records from an RRset */
    105 public synchronized void
    106 clear() {
    107 	rrs.clear();
    108 	position = 0;
    109 	nsigs = 0;
    110 }
    111 
    112 private synchronized Iterator
    113 iterator(boolean data, boolean cycle) {
    114 	int size, start, total;
    115 
    116 	total = rrs.size();
    117 
    118 	if (data)
    119 		size = total - nsigs;
    120 	else
    121 		size = nsigs;
    122 	if (size == 0)
    123 		return Collections.EMPTY_LIST.iterator();
    124 
    125 	if (data) {
    126 		if (!cycle)
    127 			start = 0;
    128 		else {
    129 			if (position >= size)
    130 				position = 0;
    131 			start = position++;
    132 		}
    133 	} else {
    134 		start = total - nsigs;
    135 	}
    136 
    137 	List list = new ArrayList(size);
    138 	if (data) {
    139 		list.addAll(rrs.subList(start, size));
    140 		if (start != 0)
    141 			list.addAll(rrs.subList(0, start));
    142 	} else {
    143 		list.addAll(rrs.subList(start, total));
    144 	}
    145 
    146 	return list.iterator();
    147 }
    148 
    149 /**
    150  * Returns an Iterator listing all (data) records.
    151  * @param cycle If true, cycle through the records so that each Iterator will
    152  * start with a different record.
    153  */
    154 public synchronized Iterator
    155 rrs(boolean cycle) {
    156 	return iterator(true, cycle);
    157 }
    158 
    159 /**
    160  * Returns an Iterator listing all (data) records.  This cycles through
    161  * the records, so each Iterator will start with a different record.
    162  */
    163 public synchronized Iterator
    164 rrs() {
    165 	return iterator(true, true);
    166 }
    167 
    168 /** Returns an Iterator listing all signature records */
    169 public synchronized Iterator
    170 sigs() {
    171 	return iterator(false, false);
    172 }
    173 
    174 /** Returns the number of (data) records */
    175 public synchronized int
    176 size() {
    177 	return rrs.size() - nsigs;
    178 }
    179 
    180 /**
    181  * Returns the name of the records
    182  * @see Name
    183  */
    184 public Name
    185 getName() {
    186 	return first().getName();
    187 }
    188 
    189 /**
    190  * Returns the type of the records
    191  * @see Type
    192  */
    193 public int
    194 getType() {
    195 	return first().getRRsetType();
    196 }
    197 
    198 /**
    199  * Returns the class of the records
    200  * @see DClass
    201  */
    202 public int
    203 getDClass() {
    204 	return first().getDClass();
    205 }
    206 
    207 /** Returns the ttl of the records */
    208 public synchronized long
    209 getTTL() {
    210 	return first().getTTL();
    211 }
    212 
    213 /**
    214  * Returns the first record
    215  * @throws IllegalStateException if the rrset is empty
    216  */
    217 public synchronized Record
    218 first() {
    219 	if (rrs.size() == 0)
    220 		throw new IllegalStateException("rrset is empty");
    221 	return (Record) rrs.get(0);
    222 }
    223 
    224 private String
    225 iteratorToString(Iterator it) {
    226 	StringBuffer sb = new StringBuffer();
    227 	while (it.hasNext()) {
    228 		Record rr = (Record) it.next();
    229 		sb.append("[");
    230 		sb.append(rr.rdataToString());
    231 		sb.append("]");
    232 		if (it.hasNext())
    233 			sb.append(" ");
    234 	}
    235 	return sb.toString();
    236 }
    237 
    238 /** Converts the RRset to a String */
    239 public String
    240 toString() {
    241 	if (rrs == null)
    242 		return ("{empty}");
    243 	StringBuffer sb = new StringBuffer();
    244 	sb.append("{ ");
    245 	sb.append(getName() + " ");
    246 	sb.append(getTTL() + " ");
    247 	sb.append(DClass.string(getDClass()) + " ");
    248 	sb.append(Type.string(getType()) + " ");
    249 	sb.append(iteratorToString(iterator(true, false)));
    250 	if (nsigs > 0) {
    251 		sb.append(" sigs: ");
    252 		sb.append(iteratorToString(iterator(false, false)));
    253 	}
    254 	sb.append(" }");
    255 	return sb.toString();
    256 }
    257 
    258 }
    259