blob: fa1a6ad2466380ee9e1971205bcb44bdbfd57165 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5import java.io.Serializable;
6import 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
17public class RRset implements Serializable {
18
19private static final long serialVersionUID = -3270249290171239695L;
20
21/*
22 * rrs contains both normal and RRSIG records, with the RRSIG records
23 * at the end.
24 */
25private List rrs;
26private short nsigs;
27private short position;
28
29/** Creates an empty RRset */
30public
31RRset() {
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 */
38public
39RRset(Record record) {
40 this();
41 safeAddRR(record);
42}
43
44/** Creates an RRset with the contents of an existing RRset */
45public
46RRset(RRset rrset) {
47 synchronized (rrset) {
48 rrs = (List) ((ArrayList)rrset.rrs).clone();
49 nsigs = rrset.nsigs;
50 position = rrset.position;
51 }
52}
53
54private void
55safeAddRR(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 */
68public synchronized void
69addRR(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 */
98public synchronized void
99deleteRR(Record r) {
100 if (rrs.remove(r) && (r instanceof RRSIGRecord))
101 nsigs--;
102}
103
104/** Deletes all Records from an RRset */
105public synchronized void
106clear() {
107 rrs.clear();
108 position = 0;
109 nsigs = 0;
110}
111
112private synchronized Iterator
113iterator(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 */
154public synchronized Iterator
155rrs(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 */
163public synchronized Iterator
164rrs() {
165 return iterator(true, true);
166}
167
168/** Returns an Iterator listing all signature records */
169public synchronized Iterator
170sigs() {
171 return iterator(false, false);
172}
173
174/** Returns the number of (data) records */
175public synchronized int
176size() {
177 return rrs.size() - nsigs;
178}
179
180/**
181 * Returns the name of the records
182 * @see Name
183 */
184public Name
185getName() {
186 return first().getName();
187}
188
189/**
190 * Returns the type of the records
191 * @see Type
192 */
193public int
194getType() {
195 return first().getRRsetType();
196}
197
198/**
199 * Returns the class of the records
200 * @see DClass
201 */
202public int
203getDClass() {
204 return first().getDClass();
205}
206
207/** Returns the ttl of the records */
208public synchronized long
209getTTL() {
210 return first().getTTL();
211}
212
213/**
214 * Returns the first record
215 * @throws IllegalStateException if the rrset is empty
216 */
217public synchronized Record
218first() {
219 if (rrs.size() == 0)
220 throw new IllegalStateException("rrset is empty");
221 return (Record) rrs.get(0);
222}
223
224private String
225iteratorToString(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 */
239public String
240toString() {
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}