• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 1999-2004 Brian Wellington (bwelling@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
RRset()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
RRset(Record record)39 RRset(Record record) {
40 	this();
41 	safeAddRR(record);
42 }
43 
44 /** Creates an RRset with the contents of an existing RRset */
45 public
RRset(RRset rrset)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
safeAddRR(Record r)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
addRR(Record r)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
deleteRR(Record r)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
clear()106 clear() {
107 	rrs.clear();
108 	position = 0;
109 	nsigs = 0;
110 }
111 
112 private synchronized Iterator
iterator(boolean data, boolean cycle)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
rrs(boolean cycle)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
rrs()164 rrs() {
165 	return iterator(true, true);
166 }
167 
168 /** Returns an Iterator listing all signature records */
169 public synchronized Iterator
sigs()170 sigs() {
171 	return iterator(false, false);
172 }
173 
174 /** Returns the number of (data) records */
175 public synchronized int
size()176 size() {
177 	return rrs.size() - nsigs;
178 }
179 
180 /**
181  * Returns the name of the records
182  * @see Name
183  */
184 public Name
getName()185 getName() {
186 	return first().getName();
187 }
188 
189 /**
190  * Returns the type of the records
191  * @see Type
192  */
193 public int
getType()194 getType() {
195 	return first().getRRsetType();
196 }
197 
198 /**
199  * Returns the class of the records
200  * @see DClass
201  */
202 public int
getDClass()203 getDClass() {
204 	return first().getDClass();
205 }
206 
207 /** Returns the ttl of the records */
208 public synchronized long
getTTL()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
first()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
iteratorToString(Iterator it)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
toString()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