~tritone-team/tritone/eucalyptus

« back to all changes in this revision

Viewing changes to clc/modules/dns/src/main/java/com/eucalyptus/dns/Zone.java

  • Committer: Bazaar Package Importer
  • Author(s): Dustin Kirkland
  • Date: 2009-12-01 21:09:28 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: james.westby@ubuntu.com-20091201210928-o2dvg0ubljhb0ft6
Tags: upstream-1.6.1~bzr1083
ImportĀ upstreamĀ versionĀ 1.6.1~bzr1083

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*******************************************************************************
2
 
*Copyright (c) 2009  Eucalyptus Systems, Inc.
3
 
4
 
*  This program is free software: you can redistribute it and/or modify
5
 
*  it under the terms of the GNU General Public License as published by
6
 
*  the Free Software Foundation, only version 3 of the License.
7
 
8
 
9
 
*  This file is distributed in the hope that it will be useful, but WITHOUT
10
 
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 
*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 
*  for more details.
13
 
14
 
*  You should have received a copy of the GNU General Public License along
15
 
*  with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
 
*  Please contact Eucalyptus Systems, Inc., 130 Castilian
18
 
*  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
19
 
*  if you need additional information or have any questions.
20
 
21
 
*  This file may incorporate work covered under the following copyright and
22
 
*  permission notice:
23
 
24
 
*    Software License Agreement (BSD License)
25
 
26
 
*    Copyright (c) 2008, Regents of the University of California
27
 
*    All rights reserved.
28
 
29
 
*    Redistribution and use of this software in source and binary forms, with
30
 
*    or without modification, are permitted provided that the following
31
 
*    conditions are met:
32
 
33
 
*      Redistributions of source code must retain the above copyright notice,
34
 
*      this list of conditions and the following disclaimer.
35
 
36
 
*      Redistributions in binary form must reproduce the above copyright
37
 
*      notice, this list of conditions and the following disclaimer in the
38
 
*      documentation and/or other materials provided with the distribution.
39
 
40
 
*    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41
 
*    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42
 
*    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43
 
*    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
44
 
*    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45
 
*    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46
 
*    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47
 
*    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48
 
*    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49
 
*    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
 
*    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
51
 
*    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
52
 
*    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
53
 
*    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
54
 
*    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
55
 
*    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
56
 
*    THE REGENTSā€™ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
57
 
*    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
58
 
*    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
59
 
*    ANY SUCH LICENSES OR RIGHTS.
60
 
*******************************************************************************/
 
2
 *Copyright (c) 2009  Eucalyptus Systems, Inc.
 
3
 * 
 
4
 *  This program is free software: you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation, only version 3 of the License.
 
7
 * 
 
8
 * 
 
9
 *  This file is distributed in the hope that it will be useful, but WITHOUT
 
10
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
12
 *  for more details.
 
13
 * 
 
14
 *  You should have received a copy of the GNU General Public License along
 
15
 *  with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 * 
 
17
 *  Please contact Eucalyptus Systems, Inc., 130 Castilian
 
18
 *  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
 
19
 *  if you need additional information or have any questions.
 
20
 * 
 
21
 *  This file may incorporate work covered under the following copyright and
 
22
 *  permission notice:
 
23
 * 
 
24
 *    Software License Agreement (BSD License)
 
25
 * 
 
26
 *    Copyright (c) 2008, Regents of the University of California
 
27
 *    All rights reserved.
 
28
 * 
 
29
 *    Redistribution and use of this software in source and binary forms, with
 
30
 *    or without modification, are permitted provided that the following
 
31
 *    conditions are met:
 
32
 * 
 
33
 *      Redistributions of source code must retain the above copyright notice,
 
34
 *      this list of conditions and the following disclaimer.
 
35
 * 
 
36
 *      Redistributions in binary form must reproduce the above copyright
 
37
 *      notice, this list of conditions and the following disclaimer in the
 
38
 *      documentation and/or other materials provided with the distribution.
 
39
 * 
 
40
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
41
 *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
42
 *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
43
 *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
44
 *    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
45
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
46
 *    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
47
 *    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
48
 *    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
49
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
50
 *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
 
51
 *    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
 
52
 *    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
 
53
 *    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
 
54
 *    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
 
55
 *    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
 
56
 *    THE REGENTSā€™ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
 
57
 *    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
 
58
 *    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
 
59
 *    ANY SUCH LICENSES OR RIGHTS.
 
60
 *******************************************************************************/
61
61
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
62
62
 
63
63
package com.eucalyptus.dns;
86
86
 
87
87
public class Zone {
88
88
 
89
 
/** A primary zone */
90
 
public static final int PRIMARY = 1;
91
 
 
92
 
/** A secondary zone */
93
 
public static final int SECONDARY = 2;
94
 
 
95
 
private Map data;
96
 
private Name origin;
97
 
private Object originNode;
98
 
private int dclass = DClass.IN;
99
 
private RRset NS;
100
 
private SOARecord SOA;
101
 
private boolean hasWild;
102
 
 
103
 
class ZoneIterator implements Iterator {
104
 
        private Iterator zentries;
105
 
        private RRset [] current;
106
 
        private int count;
107
 
        private boolean wantLastSOA;
108
 
 
109
 
        ZoneIterator(boolean axfr) {
110
 
                zentries = data.entrySet().iterator();
111
 
                wantLastSOA = axfr;
112
 
                RRset [] sets = allRRsets(originNode);
113
 
                current = new RRset[sets.length];
114
 
                for (int i = 0, j = 2; i < sets.length; i++) {
115
 
                        int type = sets[i].getType();
116
 
                        if (type == Type.SOA)
117
 
                                current[0] = sets[i];
118
 
                        else if (type == Type.NS)
119
 
                                current[1] = sets[i];
120
 
                        else
121
 
                                current[j++] = sets[i];
122
 
                }
123
 
        }
124
 
 
125
 
        public boolean
126
 
        hasNext() {
127
 
                return (current != null || wantLastSOA);
128
 
        }
129
 
 
130
 
        public Object
131
 
        next() {
132
 
                if (!hasNext()) {
133
 
                        throw new NoSuchElementException();
134
 
                }
135
 
                if (current == null && wantLastSOA) {
136
 
                        wantLastSOA = false;
137
 
                        return oneRRset(originNode, Type.SOA);
138
 
                }
139
 
                Object set = current[count++];
140
 
                if (count == current.length) {
141
 
                        current = null;
142
 
                        while (zentries.hasNext()) {
143
 
                                Map.Entry entry = (Map.Entry) zentries.next();
144
 
                                if (entry.getKey().equals(origin))
145
 
                                        continue;
146
 
                                RRset [] sets = allRRsets(entry.getValue());
147
 
                                if (sets.length == 0)
148
 
                                        continue;
149
 
                                current = sets;
150
 
                                count = 0;
151
 
                                break;
152
 
                        }
153
 
                }
154
 
                return set;
155
 
        }
156
 
 
157
 
        public void
158
 
        remove() {
159
 
                throw new UnsupportedOperationException();
160
 
        }
161
 
}
162
 
 
163
 
private void
164
 
validate() throws IOException {
165
 
        originNode = exactName(origin);
166
 
        if (originNode == null)
167
 
                throw new IOException(origin + ": no data specified");
168
 
 
169
 
        RRset rrset = oneRRset(originNode, Type.SOA);
170
 
        if (rrset == null || rrset.size() != 1)
171
 
                throw new IOException(origin +
172
 
                                      ": exactly 1 SOA must be specified");
173
 
        Iterator it = rrset.rrs();
174
 
        SOA = (SOARecord) it.next();
175
 
 
176
 
        NS = oneRRset(originNode, Type.NS);
177
 
        if (NS == null)
178
 
                throw new IOException(origin + ": no NS set specified");
179
 
}
180
 
 
181
 
private final void
182
 
maybeAddRecord(Record record) throws IOException {
183
 
        int rtype = record.getType();
184
 
        Name name = record.getName();
185
 
 
186
 
        if (rtype == Type.SOA && !name.equals(origin)) {
187
 
                throw new IOException("SOA owner " + name +
188
 
                                      " does not match zone origin " +
189
 
                                      origin);
190
 
        }
191
 
        if (name.subdomain(origin))
192
 
                addRecord(record);
193
 
}
194
 
 
195
 
/**
196
 
 * Creates a Zone from the records in the specified master file.
197
 
 * @param zone The name of the zone.
198
 
 * @param file The master file to read from.
199
 
 * @see Master
200
 
 */
201
 
public
202
 
Zone(Name zone, String file) throws IOException {
203
 
        data = new HashMap();
204
 
 
205
 
        if (zone == null)
206
 
                throw new IllegalArgumentException("no zone name specified");
207
 
        Master m = new Master(file, zone);
208
 
        Record record;
209
 
 
210
 
        origin = zone;
211
 
        while ((record = m.nextRecord()) != null)
212
 
                maybeAddRecord(record);
213
 
        validate();
214
 
}
215
 
 
216
 
/**
217
 
 * Creates a Zone from an array of records.
218
 
 * @param zone The name of the zone.
219
 
 * @param records The records to add to the zone.
220
 
 * @see Master
221
 
 */
222
 
public
223
 
Zone(Name zone, Record [] records) throws IOException {
224
 
        data = new HashMap();
225
 
 
226
 
        if (zone == null)
227
 
                throw new IllegalArgumentException("no zone name specified");
228
 
        origin = zone;
229
 
        for (int i = 0; i < records.length; i++)
230
 
                maybeAddRecord(records[i]);
231
 
        validate();
232
 
}
233
 
 
234
 
private void
235
 
fromXFR(ZoneTransferIn xfrin) throws IOException, ZoneTransferException {
236
 
        data = new HashMap();
237
 
 
238
 
        origin = xfrin.getName();
239
 
        List records = xfrin.run();
240
 
        for (Iterator it = records.iterator(); it.hasNext(); ) {
241
 
                Record record = (Record) it.next();
242
 
                maybeAddRecord(record);
243
 
        }
244
 
        if (!xfrin.isAXFR())
245
 
                throw new IllegalArgumentException("zones can only be " +
246
 
                                                   "created from AXFRs");
247
 
        validate();
248
 
}
249
 
 
250
 
/**
251
 
 * Creates a Zone by doing the specified zone transfer.
252
 
 * @param xfrin The incoming zone transfer to execute.
253
 
 * @see ZoneTransferIn
254
 
 */
255
 
public
256
 
Zone(ZoneTransferIn xfrin) throws IOException, ZoneTransferException {
257
 
        fromXFR(xfrin);
258
 
}
259
 
 
260
 
/**
261
 
 * Creates a Zone by performing a zone transfer to the specified host.
262
 
 * @see ZoneTransferIn
263
 
 */
264
 
public
265
 
Zone(Name zone, int dclass, String remote)
266
 
throws IOException, ZoneTransferException
267
 
{
268
 
        ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(zone, remote, null);
269
 
        xfrin.setDClass(dclass);
270
 
        fromXFR(xfrin);
271
 
}
272
 
 
273
 
/** Returns the Zone's origin */
274
 
public Name
275
 
getOrigin() {
276
 
        return origin;
277
 
}
278
 
 
279
 
/** Returns the Zone origin's NS records */
280
 
public RRset
281
 
getNS() {
282
 
        return NS;
283
 
}
284
 
 
285
 
/** Returns the Zone's SOA record */
286
 
public SOARecord
287
 
getSOA() {
288
 
        return SOA;
289
 
}
290
 
 
291
 
/** Returns the Zone's class */
292
 
public int
293
 
getDClass() {
294
 
        return dclass;
295
 
}
296
 
 
297
 
private synchronized Object
298
 
exactName(Name name) {
299
 
        return data.get(name);
300
 
}
301
 
 
302
 
private synchronized RRset []
303
 
allRRsets(Object types) {
304
 
        if (types instanceof List) {
305
 
                List typelist = (List) types;
306
 
                return (RRset []) typelist.toArray(new RRset[typelist.size()]);
307
 
        } else {
308
 
                RRset set = (RRset) types;
309
 
                return new RRset [] {set};
310
 
        }
311
 
}
312
 
 
313
 
private synchronized RRset
314
 
oneRRset(Object types, int type) {
315
 
        if (type == Type.ANY)
316
 
                throw new IllegalArgumentException("oneRRset(ANY)");
317
 
        if (types instanceof List) {
318
 
                List list = (List) types;
319
 
                for (int i = 0; i < list.size(); i++) {
320
 
                        RRset set = (RRset) list.get(i);
 
89
        /** A primary zone */
 
90
        public static final int PRIMARY = 1;
 
91
 
 
92
        /** A secondary zone */
 
93
        public static final int SECONDARY = 2;
 
94
 
 
95
        private Map data;
 
96
        private Name origin;
 
97
        private Object originNode;
 
98
        private int dclass = DClass.IN;
 
99
        private RRset NS;
 
100
        private SOARecord SOA;
 
101
        private boolean hasWild;
 
102
 
 
103
        class ZoneIterator implements Iterator {
 
104
                private Iterator zentries;
 
105
                private RRset [] current;
 
106
                private int count;
 
107
                private boolean wantLastSOA;
 
108
 
 
109
                ZoneIterator(boolean axfr) {
 
110
                        zentries = data.entrySet().iterator();
 
111
                        wantLastSOA = axfr;
 
112
                        RRset [] sets = allRRsets(originNode);
 
113
                        current = new RRset[sets.length];
 
114
                        for (int i = 0, j = 2; i < sets.length; i++) {
 
115
                                int type = sets[i].getType();
 
116
                                if (type == Type.SOA)
 
117
                                        current[0] = sets[i];
 
118
                                else if (type == Type.NS)
 
119
                                        current[1] = sets[i];
 
120
                                else
 
121
                                        current[j++] = sets[i];
 
122
                        }
 
123
                }
 
124
 
 
125
                public boolean
 
126
                hasNext() {
 
127
                        return (current != null || wantLastSOA);
 
128
                }
 
129
 
 
130
                public Object
 
131
                next() {
 
132
                        if (!hasNext()) {
 
133
                                throw new NoSuchElementException();
 
134
                        }
 
135
                        if (current == null && wantLastSOA) {
 
136
                                wantLastSOA = false;
 
137
                                return oneRRset(originNode, Type.SOA);
 
138
                        }
 
139
                        if(current != null) {
 
140
                                Object set = current[count++];
 
141
                                if (count == current.length) {
 
142
                                        current = null;
 
143
                                        while (zentries.hasNext()) {
 
144
                                                Map.Entry entry = (Map.Entry) zentries.next();
 
145
                                                if (entry.getKey().equals(origin))
 
146
                                                        continue;
 
147
                                                RRset [] sets = allRRsets(entry.getValue());
 
148
                                                if (sets.length == 0)
 
149
                                                        continue;
 
150
                                                current = sets;
 
151
                                                count = 0;
 
152
                                                break;
 
153
                                        }
 
154
                                }               
 
155
                                return set;
 
156
                        }
 
157
                        return null;
 
158
                }
 
159
 
 
160
                public void
 
161
                remove() {
 
162
                        throw new UnsupportedOperationException();
 
163
                }
 
164
        }
 
165
 
 
166
        private void
 
167
        validate() throws IOException {
 
168
                originNode = exactName(origin);
 
169
                if (originNode == null)
 
170
                        throw new IOException(origin + ": no data specified");
 
171
 
 
172
                RRset rrset = oneRRset(originNode, Type.SOA);
 
173
                if (rrset == null || rrset.size() != 1)
 
174
                        throw new IOException(origin +
 
175
                        ": exactly 1 SOA must be specified");
 
176
                Iterator it = rrset.rrs();
 
177
                SOA = (SOARecord) it.next();
 
178
 
 
179
                NS = oneRRset(originNode, Type.NS);
 
180
                if (NS == null)
 
181
                        throw new IOException(origin + ": no NS set specified");
 
182
        }
 
183
 
 
184
        private final void
 
185
        maybeAddRecord(Record record) throws IOException {
 
186
                int rtype = record.getType();
 
187
                Name name = record.getName();
 
188
 
 
189
                if (rtype == Type.SOA && !name.equals(origin)) {
 
190
                        throw new IOException("SOA owner " + name +
 
191
                                        " does not match zone origin " +
 
192
                                        origin);
 
193
                }
 
194
                if (name.subdomain(origin))
 
195
                        addRecord(record);
 
196
        }
 
197
 
 
198
        /**
 
199
         * Creates a Zone from the records in the specified master file.
 
200
         * @param zone The name of the zone.
 
201
         * @param file The master file to read from.
 
202
         * @see Master
 
203
         */
 
204
        public
 
205
        Zone(Name zone, String file) throws IOException {
 
206
                data = new HashMap();
 
207
 
 
208
                if (zone == null)
 
209
                        throw new IllegalArgumentException("no zone name specified");
 
210
                Master m = new Master(file, zone);
 
211
                Record record;
 
212
 
 
213
                origin = zone;
 
214
                while ((record = m.nextRecord()) != null)
 
215
                        maybeAddRecord(record);
 
216
                validate();
 
217
        }
 
218
 
 
219
        /**
 
220
         * Creates a Zone from an array of records.
 
221
         * @param zone The name of the zone.
 
222
         * @param records The records to add to the zone.
 
223
         * @see Master
 
224
         */
 
225
        public
 
226
        Zone(Name zone, Record [] records) throws IOException {
 
227
                data = new HashMap();
 
228
 
 
229
                if (zone == null)
 
230
                        throw new IllegalArgumentException("no zone name specified");
 
231
                origin = zone;
 
232
                for (int i = 0; i < records.length; i++)
 
233
                        maybeAddRecord(records[i]);
 
234
                validate();
 
235
        }
 
236
 
 
237
        private void
 
238
        fromXFR(ZoneTransferIn xfrin) throws IOException, ZoneTransferException {
 
239
                data = new HashMap();
 
240
 
 
241
                origin = xfrin.getName();
 
242
                List records = xfrin.run();
 
243
                for (Iterator it = records.iterator(); it.hasNext(); ) {
 
244
                        Record record = (Record) it.next();
 
245
                        maybeAddRecord(record);
 
246
                }
 
247
                if (!xfrin.isAXFR())
 
248
                        throw new IllegalArgumentException("zones can only be " +
 
249
                        "created from AXFRs");
 
250
                validate();
 
251
        }
 
252
 
 
253
        /**
 
254
         * Creates a Zone by doing the specified zone transfer.
 
255
         * @param xfrin The incoming zone transfer to execute.
 
256
         * @see ZoneTransferIn
 
257
         */
 
258
        public
 
259
        Zone(ZoneTransferIn xfrin) throws IOException, ZoneTransferException {
 
260
                fromXFR(xfrin);
 
261
        }
 
262
 
 
263
        /**
 
264
         * Creates a Zone by performing a zone transfer to the specified host.
 
265
         * @see ZoneTransferIn
 
266
         */
 
267
        public
 
268
        Zone(Name zone, int dclass, String remote)
 
269
        throws IOException, ZoneTransferException
 
270
        {
 
271
                ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(zone, remote, null);
 
272
                xfrin.setDClass(dclass);
 
273
                fromXFR(xfrin);
 
274
        }
 
275
 
 
276
        /** Returns the Zone's origin */
 
277
        public Name
 
278
        getOrigin() {
 
279
                return origin;
 
280
        }
 
281
 
 
282
        /** Returns the Zone origin's NS records */
 
283
        public RRset
 
284
        getNS() {
 
285
                return NS;
 
286
        }
 
287
 
 
288
        /** Returns the Zone's SOA record */
 
289
        public SOARecord
 
290
        getSOA() {
 
291
                return SOA;
 
292
        }
 
293
 
 
294
        /** Returns the Zone's class */
 
295
        public int
 
296
        getDClass() {
 
297
                return dclass;
 
298
        }
 
299
 
 
300
        private synchronized Object
 
301
        exactName(Name name) {
 
302
                return data.get(name);
 
303
        }
 
304
 
 
305
        private synchronized RRset []
 
306
                                    allRRsets(Object types) {
 
307
                if (types instanceof List) {
 
308
                        List typelist = (List) types;
 
309
                        return (RRset []) typelist.toArray(new RRset[typelist.size()]);
 
310
                } else {
 
311
                        RRset set = (RRset) types;
 
312
                        return new RRset [] {set};
 
313
                }
 
314
        }
 
315
 
 
316
        private synchronized RRset
 
317
        oneRRset(Object types, int type) {
 
318
                if (type == Type.ANY)
 
319
                        throw new IllegalArgumentException("oneRRset(ANY)");
 
320
                if (types instanceof List) {
 
321
                        List list = (List) types;
 
322
                        for (int i = 0; i < list.size(); i++) {
 
323
                                RRset set = (RRset) list.get(i);
 
324
                                if (set.getType() == type)
 
325
                                        return set;
 
326
                        }
 
327
                } else {
 
328
                        RRset set = (RRset) types;
321
329
                        if (set.getType() == type)
322
330
                                return set;
323
331
                }
324
 
        } else {
325
 
                RRset set = (RRset) types;
326
 
                if (set.getType() == type)
327
 
                        return set;
328
 
        }
329
 
        return null;
330
 
}
331
 
 
332
 
private synchronized RRset
333
 
findRRset(Name name, int type) {
334
 
        Object types = exactName(name);
335
 
        if (types == null)
336
332
                return null;
337
 
        return oneRRset(types, type);
338
 
}
339
 
 
340
 
private synchronized void
341
 
addRRset(Name name, RRset rrset) {
342
 
        if (!hasWild && name.isWild())
343
 
                hasWild = true;
344
 
        Object types = data.get(name);
345
 
        if (types == null) {
346
 
                data.put(name, rrset);
347
 
                return;
348
 
        }
349
 
        int rtype = rrset.getType();
350
 
        if (types instanceof List) {
351
 
                List list = (List) types;
352
 
                for (int i = 0; i < list.size(); i++) {
353
 
                        RRset set = (RRset) list.get(i);
354
 
                        if (set.getType() == rtype) {
355
 
                                list.set(i, rrset);
356
 
                                return;
357
 
                        }
358
 
                }
359
 
                list.add(rrset);
360
 
        } else {
361
 
                RRset set = (RRset) types;
362
 
                if (set.getType() == rtype)
 
333
        }
 
334
 
 
335
        private synchronized RRset
 
336
        findRRset(Name name, int type) {
 
337
                Object types = exactName(name);
 
338
                if (types == null)
 
339
                        return null;
 
340
                return oneRRset(types, type);
 
341
        }
 
342
 
 
343
        private synchronized void
 
344
        addRRset(Name name, RRset rrset) {
 
345
                if (!hasWild && name.isWild())
 
346
                        hasWild = true;
 
347
                Object types = data.get(name);
 
348
                if (types == null) {
363
349
                        data.put(name, rrset);
364
 
                else {
365
 
                        LinkedList list = new LinkedList();
366
 
                        list.add(set);
 
350
                        return;
 
351
                }
 
352
                int rtype = rrset.getType();
 
353
                if (types instanceof List) {
 
354
                        List list = (List) types;
 
355
                        for (int i = 0; i < list.size(); i++) {
 
356
                                RRset set = (RRset) list.get(i);
 
357
                                if (set.getType() == rtype) {
 
358
                                        list.set(i, rrset);
 
359
                                        return;
 
360
                                }
 
361
                        }
367
362
                        list.add(rrset);
368
 
                        data.put(name, list);
 
363
                } else {
 
364
                        RRset set = (RRset) types;
 
365
                        if (set.getType() == rtype)
 
366
                                data.put(name, rrset);
 
367
                        else {
 
368
                                LinkedList list = new LinkedList();
 
369
                                list.add(set);
 
370
                                list.add(rrset);
 
371
                                data.put(name, list);
 
372
                        }
369
373
                }
370
374
        }
371
 
}
372
375
 
373
 
private synchronized void
374
 
removeRRset(Name name, int type) {
375
 
        Object types = data.get(name);
376
 
        if (types == null) {
377
 
                return;
378
 
        }
379
 
        if (types instanceof List) {
380
 
                List list = (List) types;
381
 
                for (int i = 0; i < list.size(); i++) {
382
 
                        RRset set = (RRset) list.get(i);
383
 
                        if (set.getType() == type) {
384
 
                                list.remove(i);
385
 
                                if (list.size() == 0)
386
 
                                        data.remove(name);
 
376
        private synchronized void
 
377
        removeRRset(Name name, int type) {
 
378
                Object types = data.get(name);
 
379
                if (types == null) {
 
380
                        return;
 
381
                }
 
382
                if (types instanceof List) {
 
383
                        List list = (List) types;
 
384
                        for (int i = 0; i < list.size(); i++) {
 
385
                                RRset set = (RRset) list.get(i);
 
386
                                if (set.getType() == type) {
 
387
                                        list.remove(i);
 
388
                                        if (list.size() == 0)
 
389
                                                data.remove(name);
 
390
                                        return;
 
391
                                }
 
392
                        }
 
393
                } else {
 
394
                        RRset set = (RRset) types;
 
395
                        if (set.getType() != type)
387
396
                                return;
388
 
                        }
389
 
                }
390
 
        } else {
391
 
                RRset set = (RRset) types;
392
 
                if (set.getType() != type)
393
 
                        return;
394
 
                data.remove(name);
395
 
        }
396
 
}
397
 
 
398
 
private synchronized SetResponse
399
 
lookup(Name name, int type) {
400
 
        int labels;
401
 
        int olabels;
402
 
        int tlabels;
403
 
        RRset rrset;
404
 
        Name tname;
405
 
        Object types;
406
 
        SetResponse sr;
407
 
 
408
 
        if (!name.subdomain(origin))
409
 
                return SetResponse.ofType(SetResponse.NXDOMAIN);
410
 
 
411
 
        labels = name.labels();
412
 
        olabels = origin.labels();
413
 
 
414
 
        for (tlabels = olabels; tlabels <= labels; tlabels++) {
415
 
                boolean isOrigin = (tlabels == olabels);
416
 
                boolean isExact = (tlabels == labels);
417
 
 
418
 
                if (isOrigin)
419
 
                        tname = origin;
420
 
                else if (isExact)
421
 
                        tname = name;
422
 
                else
423
 
                        tname = new Name(name, labels - tlabels);
424
 
 
425
 
                types = exactName(tname);
426
 
                if (types == null)
427
 
                        continue;
428
 
 
429
 
                /* If this is a delegation, return that. */
430
 
                if (!isOrigin) {
431
 
                        RRset ns = oneRRset(types, Type.NS);
432
 
                        if (ns != null)
433
 
                                return new SetResponse(SetResponse.DELEGATION,
434
 
                                                       ns);
435
 
                }
436
 
 
437
 
                /* If this is an ANY lookup, return everything. */
438
 
                if (isExact && type == Type.ANY) {
439
 
                        sr = new SetResponse(SetResponse.SUCCESSFUL);
440
 
                        RRset [] sets = allRRsets(types);
441
 
                        for (int i = 0; i < sets.length; i++)
442
 
                                sr.addRRset(sets[i]);
443
 
                        return sr;
444
 
                }
445
 
 
446
 
                /*
447
 
                 * If this is the name, look for the actual type or a CNAME.
448
 
                 * Otherwise, look for a DNAME.
449
 
                 */
450
 
                if (isExact) {
451
 
                        rrset = oneRRset(types, type);
452
 
                        if (rrset != null) {
453
 
                                sr = new SetResponse(SetResponse.SUCCESSFUL);
454
 
                                sr.addRRset(rrset);
455
 
                                return sr;
456
 
                        }
457
 
                        rrset = oneRRset(types, Type.CNAME);
458
 
                        if (rrset != null)
459
 
                                return new SetResponse(SetResponse.CNAME,
460
 
                                                       rrset);
461
 
                } else {
462
 
                        rrset = oneRRset(types, Type.DNAME);
463
 
                        if (rrset != null)
464
 
                                return new SetResponse(SetResponse.DNAME,
465
 
                                                       rrset);
466
 
                }
467
 
 
468
 
                /* We found the name, but not the type. */
469
 
                if (isExact)
470
 
                        return SetResponse.ofType(SetResponse.NXRRSET);
471
 
        }
472
 
 
473
 
        if (hasWild) {
474
 
                for (int i = 0; i < labels - olabels; i++) {
475
 
                        tname = name.wild(i + 1);
 
397
                        data.remove(name);
 
398
                }
 
399
        }
 
400
 
 
401
        private synchronized SetResponse
 
402
        lookup(Name name, int type) {
 
403
                int labels;
 
404
                int olabels;
 
405
                int tlabels;
 
406
                RRset rrset;
 
407
                Name tname;
 
408
                Object types;
 
409
                SetResponse sr;
 
410
 
 
411
                if (!name.subdomain(origin))
 
412
                        return SetResponse.ofType(SetResponse.NXDOMAIN);
 
413
 
 
414
                labels = name.labels();
 
415
                olabels = origin.labels();
 
416
 
 
417
                for (tlabels = olabels; tlabels <= labels; tlabels++) {
 
418
                        boolean isOrigin = (tlabels == olabels);
 
419
                        boolean isExact = (tlabels == labels);
 
420
 
 
421
                        if (isOrigin)
 
422
                                tname = origin;
 
423
                        else if (isExact)
 
424
                                tname = name;
 
425
                        else
 
426
                                tname = new Name(name, labels - tlabels);
476
427
 
477
428
                        types = exactName(tname);
478
429
                        if (types == null)
479
430
                                continue;
480
431
 
481
 
                        rrset = oneRRset(types, type);
482
 
                        if (rrset != null) {
 
432
                        /* If this is a delegation, return that. */
 
433
                        if (!isOrigin) {
 
434
                                RRset ns = oneRRset(types, Type.NS);
 
435
                                if (ns != null)
 
436
                                        return new SetResponse(SetResponse.DELEGATION,
 
437
                                                        ns);
 
438
                        }
 
439
 
 
440
                        /* If this is an ANY lookup, return everything. */
 
441
                        if (isExact && type == Type.ANY) {
483
442
                                sr = new SetResponse(SetResponse.SUCCESSFUL);
484
 
                                sr.addRRset(rrset);
 
443
                                RRset [] sets = allRRsets(types);
 
444
                                for (int i = 0; i < sets.length; i++)
 
445
                                        sr.addRRset(sets[i]);
485
446
                                return sr;
486
447
                        }
487
 
                }
488
 
        }
489
 
 
490
 
        return SetResponse.ofType(SetResponse.NXDOMAIN);
491
 
}
492
 
 
493
 
/**     
494
 
 * Looks up Records in the Zone.  This follows CNAMEs and wildcards.
495
 
 * @param name The name to look up
496
 
 * @param type The type to look up
497
 
 * @return A SetResponse object
498
 
 * @see SetResponse
499
 
 */ 
500
 
public SetResponse
501
 
findRecords(Name name, int type) {
502
 
        return lookup(name, type);
503
 
}
504
 
 
505
 
/**
506
 
 * Looks up Records in the zone, finding exact matches only.
507
 
 * @param name The name to look up
508
 
 * @param type The type to look up
509
 
 * @return The matching RRset
510
 
 * @see RRset
511
 
 */ 
512
 
public RRset
513
 
findExactMatch(Name name, int type) {
514
 
        Object types = exactName(name);
515
 
        if (types == null)
516
 
                return null;
517
 
        return oneRRset(types, type);
518
 
}
519
 
 
520
 
/**
521
 
 * Adds an RRset to the Zone
522
 
 * @param rrset The RRset to be added
523
 
 * @see RRset
524
 
 */
525
 
public void
526
 
addRRset(RRset rrset) {
527
 
        Name name = rrset.getName();
528
 
        addRRset(name, rrset);
529
 
}
530
 
 
531
 
/**
532
 
 * Adds a Record to the Zone
533
 
 * @param r The record to be added
534
 
 * @see Record
535
 
 */
536
 
public void
537
 
addRecord(Record r) {
538
 
        Name name = r.getName();
539
 
        int rtype = r.getRRsetType();
540
 
        synchronized (this) {
541
 
                RRset rrset = findRRset(name, rtype);
542
 
                if (rrset == null) {
543
 
                        rrset = new RRset(r);
544
 
                        addRRset(name, rrset);
545
 
                } else {
546
 
                        rrset.addRR(r);
547
 
                }
548
 
        }
549
 
}
550
 
 
551
 
/**
552
 
 * Removes a record from the Zone
553
 
 * @param r The record to be removed
554
 
 * @see Record
555
 
 */
556
 
public void
557
 
removeRecord(Record r) {
558
 
        Name name = r.getName();
559
 
        int rtype = r.getRRsetType();
560
 
        synchronized (this) {
561
 
                RRset rrset = findRRset(name, rtype);
562
 
                if (rrset == null)
563
 
                        return;
564
 
                if (rrset.size() == 1 && rrset.first().equals(r))
565
 
                        removeRRset(name, rtype);
566
 
                else
567
 
                        rrset.deleteRR(r);
568
 
        }
569
 
}
570
 
 
571
 
/**
572
 
 * Returns an Iterator over the RRsets in the zone.
573
 
 */
574
 
public Iterator
575
 
iterator() {
576
 
        return new ZoneIterator(false);
577
 
}
578
 
 
579
 
/**
580
 
 * Returns an Iterator over the RRsets in the zone that can be used to
581
 
 * construct an AXFR response.  This is identical to {@link #iterator} except
582
 
 * that the SOA is returned at the end as well as the beginning.
583
 
 */
584
 
public Iterator
585
 
AXFR() {
586
 
        return new ZoneIterator(true);
587
 
}
588
 
 
589
 
private void
590
 
nodeToString(StringBuffer sb, Object node) {
591
 
        RRset [] sets = allRRsets(node);
592
 
        for (int i = 0; i < sets.length; i++) {
593
 
                RRset rrset = sets[i];
594
 
                Iterator it = rrset.rrs();
595
 
                while (it.hasNext())
596
 
                        sb.append(it.next() + "\n");
597
 
                it = rrset.sigs();
598
 
                while (it.hasNext())
599
 
                        sb.append(it.next() + "\n");
600
 
        }
601
 
}
602
 
 
603
 
/**
604
 
 * Returns the contents of the Zone in master file format.
605
 
 */
606
 
public String
607
 
toMasterFile() {
608
 
        Iterator zentries = data.entrySet().iterator();
609
 
        StringBuffer sb = new StringBuffer();
610
 
        nodeToString(sb, originNode);
611
 
        while (zentries.hasNext()) {
612
 
                Map.Entry entry = (Map.Entry) zentries.next();
613
 
                if (!origin.equals(entry.getKey()))
614
 
                        nodeToString(sb, entry.getValue());
615
 
        }
616
 
        return sb.toString();
617
 
}
618
 
 
619
 
/**
620
 
 * Returns the contents of the Zone as a string (in master file format).
621
 
 */
622
 
public String
623
 
toString() {
624
 
        return toMasterFile();
625
 
}
 
448
 
 
449
                        /*
 
450
                         * If this is the name, look for the actual type or a CNAME.
 
451
                         * Otherwise, look for a DNAME.
 
452
                         */
 
453
                        if (isExact) {
 
454
                                rrset = oneRRset(types, type);
 
455
                                if (rrset != null) {
 
456
                                        sr = new SetResponse(SetResponse.SUCCESSFUL);
 
457
                                        sr.addRRset(rrset);
 
458
                                        return sr;
 
459
                                }
 
460
                                rrset = oneRRset(types, Type.CNAME);
 
461
                                if (rrset != null)
 
462
                                        return new SetResponse(SetResponse.CNAME,
 
463
                                                        rrset);
 
464
                        } else {
 
465
                                rrset = oneRRset(types, Type.DNAME);
 
466
                                if (rrset != null)
 
467
                                        return new SetResponse(SetResponse.DNAME,
 
468
                                                        rrset);
 
469
                        }
 
470
 
 
471
                        /* We found the name, but not the type. */
 
472
                        if (isExact)
 
473
                                return SetResponse.ofType(SetResponse.NXRRSET);
 
474
                }
 
475
 
 
476
                if (hasWild) {
 
477
                        for (int i = 0; i < labels - olabels; i++) {
 
478
                                tname = name.wild(i + 1);
 
479
 
 
480
                                types = exactName(tname);
 
481
                                if (types == null)
 
482
                                        continue;
 
483
 
 
484
                                rrset = oneRRset(types, type);
 
485
                                if (rrset != null) {
 
486
                                        sr = new SetResponse(SetResponse.SUCCESSFUL);
 
487
                                        sr.addRRset(rrset);
 
488
                                        return sr;
 
489
                                }
 
490
                        }
 
491
                }
 
492
 
 
493
                return SetResponse.ofType(SetResponse.NXDOMAIN);
 
494
        }
 
495
 
 
496
        /**     
 
497
         * Looks up Records in the Zone.  This follows CNAMEs and wildcards.
 
498
         * @param name The name to look up
 
499
         * @param type The type to look up
 
500
         * @return A SetResponse object
 
501
         * @see SetResponse
 
502
         */ 
 
503
        public SetResponse
 
504
        findRecords(Name name, int type) {
 
505
                return lookup(name, type);
 
506
        }
 
507
 
 
508
        /**
 
509
         * Looks up Records in the zone, finding exact matches only.
 
510
         * @param name The name to look up
 
511
         * @param type The type to look up
 
512
         * @return The matching RRset
 
513
         * @see RRset
 
514
         */ 
 
515
        public RRset
 
516
        findExactMatch(Name name, int type) {
 
517
                Object types = exactName(name);
 
518
                if (types == null)
 
519
                        return null;
 
520
                return oneRRset(types, type);
 
521
        }
 
522
 
 
523
        /**
 
524
         * Adds an RRset to the Zone
 
525
         * @param rrset The RRset to be added
 
526
         * @see RRset
 
527
         */
 
528
        public void
 
529
        addRRset(RRset rrset) {
 
530
                Name name = rrset.getName();
 
531
                addRRset(name, rrset);
 
532
        }
 
533
 
 
534
        /**
 
535
         * Adds a Record to the Zone
 
536
         * @param r The record to be added
 
537
         * @see Record
 
538
         */
 
539
        public void
 
540
        addRecord(Record r) {
 
541
                Name name = r.getName();
 
542
                int rtype = r.getRRsetType();
 
543
                synchronized (this) {
 
544
                        RRset rrset = findRRset(name, rtype);
 
545
                        if (rrset == null) {
 
546
                                rrset = new RRset(r);
 
547
                                addRRset(name, rrset);
 
548
                        } else {
 
549
                                rrset.addRR(r);
 
550
                        }
 
551
                }
 
552
        }
 
553
 
 
554
        /**
 
555
         * Removes a record from the Zone
 
556
         * @param r The record to be removed
 
557
         * @see Record
 
558
         */
 
559
        public void
 
560
        removeRecord(Record r) {
 
561
                Name name = r.getName();
 
562
                int rtype = r.getRRsetType();
 
563
                synchronized (this) {
 
564
                        RRset rrset = findRRset(name, rtype);
 
565
                        if (rrset == null)
 
566
                                return;
 
567
                        if (rrset.size() == 1 && rrset.first().equals(r))
 
568
                                removeRRset(name, rtype);
 
569
                        else
 
570
                                rrset.deleteRR(r);
 
571
                }
 
572
        }
 
573
 
 
574
        /**
 
575
         * Returns an Iterator over the RRsets in the zone.
 
576
         */
 
577
        public Iterator
 
578
        iterator() {
 
579
                return new ZoneIterator(false);
 
580
        }
 
581
 
 
582
        /**
 
583
         * Returns an Iterator over the RRsets in the zone that can be used to
 
584
         * construct an AXFR response.  This is identical to {@link #iterator} except
 
585
         * that the SOA is returned at the end as well as the beginning.
 
586
         */
 
587
        public Iterator
 
588
        AXFR() {
 
589
                return new ZoneIterator(true);
 
590
        }
 
591
 
 
592
        private void
 
593
        nodeToString(StringBuffer sb, Object node) {
 
594
                RRset [] sets = allRRsets(node);
 
595
                for (int i = 0; i < sets.length; i++) {
 
596
                        RRset rrset = sets[i];
 
597
                        Iterator it = rrset.rrs();
 
598
                        while (it.hasNext())
 
599
                                sb.append(it.next() + "\n");
 
600
                        it = rrset.sigs();
 
601
                        while (it.hasNext())
 
602
                                sb.append(it.next() + "\n");
 
603
                }
 
604
        }
 
605
 
 
606
        /**
 
607
         * Returns the contents of the Zone in master file format.
 
608
         */
 
609
        public String
 
610
        toMasterFile() {
 
611
                Iterator zentries = data.entrySet().iterator();
 
612
                StringBuffer sb = new StringBuffer();
 
613
                nodeToString(sb, originNode);
 
614
                while (zentries.hasNext()) {
 
615
                        Map.Entry entry = (Map.Entry) zentries.next();
 
616
                        if (!origin.equals(entry.getKey()))
 
617
                                nodeToString(sb, entry.getValue());
 
618
                }
 
619
                return sb.toString();
 
620
        }
 
621
 
 
622
        /**
 
623
         * Returns the contents of the Zone as a string (in master file format).
 
624
         */
 
625
        public String
 
626
        toString() {
 
627
                return toMasterFile();
 
628
        }
626
629
 
627
630
}