| // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) |
| |
| package org.xbill.DNS; |
| |
| import java.io.Serializable; |
| import java.util.*; |
| |
| /** |
| * A set of Records with the same name, type, and class. Also included |
| * are all RRSIG records signing the data records. |
| * @see Record |
| * @see RRSIGRecord |
| * |
| * @author Brian Wellington |
| */ |
| |
| public class RRset implements Serializable { |
| |
| private static final long serialVersionUID = -3270249290171239695L; |
| |
| /* |
| * rrs contains both normal and RRSIG records, with the RRSIG records |
| * at the end. |
| */ |
| private List rrs; |
| private short nsigs; |
| private short position; |
| |
| /** Creates an empty RRset */ |
| public |
| RRset() { |
| rrs = new ArrayList(1); |
| nsigs = 0; |
| position = 0; |
| } |
| |
| /** Creates an RRset and sets its contents to the specified record */ |
| public |
| RRset(Record record) { |
| this(); |
| safeAddRR(record); |
| } |
| |
| /** Creates an RRset with the contents of an existing RRset */ |
| public |
| RRset(RRset rrset) { |
| synchronized (rrset) { |
| rrs = (List) ((ArrayList)rrset.rrs).clone(); |
| nsigs = rrset.nsigs; |
| position = rrset.position; |
| } |
| } |
| |
| private void |
| safeAddRR(Record r) { |
| if (!(r instanceof RRSIGRecord)) { |
| if (nsigs == 0) |
| rrs.add(r); |
| else |
| rrs.add(rrs.size() - nsigs, r); |
| } else { |
| rrs.add(r); |
| nsigs++; |
| } |
| } |
| |
| /** Adds a Record to an RRset */ |
| public synchronized void |
| addRR(Record r) { |
| if (rrs.size() == 0) { |
| safeAddRR(r); |
| return; |
| } |
| Record first = first(); |
| if (!r.sameRRset(first)) |
| throw new IllegalArgumentException("record does not match " + |
| "rrset"); |
| |
| if (r.getTTL() != first.getTTL()) { |
| if (r.getTTL() > first.getTTL()) { |
| r = r.cloneRecord(); |
| r.setTTL(first.getTTL()); |
| } else { |
| for (int i = 0; i < rrs.size(); i++) { |
| Record tmp = (Record) rrs.get(i); |
| tmp = tmp.cloneRecord(); |
| tmp.setTTL(r.getTTL()); |
| rrs.set(i, tmp); |
| } |
| } |
| } |
| |
| if (!rrs.contains(r)) |
| safeAddRR(r); |
| } |
| |
| /** Deletes a Record from an RRset */ |
| public synchronized void |
| deleteRR(Record r) { |
| if (rrs.remove(r) && (r instanceof RRSIGRecord)) |
| nsigs--; |
| } |
| |
| /** Deletes all Records from an RRset */ |
| public synchronized void |
| clear() { |
| rrs.clear(); |
| position = 0; |
| nsigs = 0; |
| } |
| |
| private synchronized Iterator |
| iterator(boolean data, boolean cycle) { |
| int size, start, total; |
| |
| total = rrs.size(); |
| |
| if (data) |
| size = total - nsigs; |
| else |
| size = nsigs; |
| if (size == 0) |
| return Collections.EMPTY_LIST.iterator(); |
| |
| if (data) { |
| if (!cycle) |
| start = 0; |
| else { |
| if (position >= size) |
| position = 0; |
| start = position++; |
| } |
| } else { |
| start = total - nsigs; |
| } |
| |
| List list = new ArrayList(size); |
| if (data) { |
| list.addAll(rrs.subList(start, size)); |
| if (start != 0) |
| list.addAll(rrs.subList(0, start)); |
| } else { |
| list.addAll(rrs.subList(start, total)); |
| } |
| |
| return list.iterator(); |
| } |
| |
| /** |
| * Returns an Iterator listing all (data) records. |
| * @param cycle If true, cycle through the records so that each Iterator will |
| * start with a different record. |
| */ |
| public synchronized Iterator |
| rrs(boolean cycle) { |
| return iterator(true, cycle); |
| } |
| |
| /** |
| * Returns an Iterator listing all (data) records. This cycles through |
| * the records, so each Iterator will start with a different record. |
| */ |
| public synchronized Iterator |
| rrs() { |
| return iterator(true, true); |
| } |
| |
| /** Returns an Iterator listing all signature records */ |
| public synchronized Iterator |
| sigs() { |
| return iterator(false, false); |
| } |
| |
| /** Returns the number of (data) records */ |
| public synchronized int |
| size() { |
| return rrs.size() - nsigs; |
| } |
| |
| /** |
| * Returns the name of the records |
| * @see Name |
| */ |
| public Name |
| getName() { |
| return first().getName(); |
| } |
| |
| /** |
| * Returns the type of the records |
| * @see Type |
| */ |
| public int |
| getType() { |
| return first().getRRsetType(); |
| } |
| |
| /** |
| * Returns the class of the records |
| * @see DClass |
| */ |
| public int |
| getDClass() { |
| return first().getDClass(); |
| } |
| |
| /** Returns the ttl of the records */ |
| public synchronized long |
| getTTL() { |
| return first().getTTL(); |
| } |
| |
| /** |
| * Returns the first record |
| * @throws IllegalStateException if the rrset is empty |
| */ |
| public synchronized Record |
| first() { |
| if (rrs.size() == 0) |
| throw new IllegalStateException("rrset is empty"); |
| return (Record) rrs.get(0); |
| } |
| |
| private String |
| iteratorToString(Iterator it) { |
| StringBuffer sb = new StringBuffer(); |
| while (it.hasNext()) { |
| Record rr = (Record) it.next(); |
| sb.append("["); |
| sb.append(rr.rdataToString()); |
| sb.append("]"); |
| if (it.hasNext()) |
| sb.append(" "); |
| } |
| return sb.toString(); |
| } |
| |
| /** Converts the RRset to a String */ |
| public String |
| toString() { |
| if (rrs == null) |
| return ("{empty}"); |
| StringBuffer sb = new StringBuffer(); |
| sb.append("{ "); |
| sb.append(getName() + " "); |
| sb.append(getTTL() + " "); |
| sb.append(DClass.string(getDClass()) + " "); |
| sb.append(Type.string(getType()) + " "); |
| sb.append(iteratorToString(iterator(true, false))); |
| if (nsigs > 0) { |
| sb.append(" sigs: "); |
| sb.append(iteratorToString(iterator(false, false))); |
| } |
| sb.append(" }"); |
| return sb.toString(); |
| } |
| |
| } |