|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.jndi.dns; |
|
|
|
|
|
import java.lang.ref.SoftReference; |
|
import java.util.Date; |
|
import java.util.Vector; |
|
|
|
|
|
/** |
|
* ZoneNode extends NameNode to represent a tree of the zones in the |
|
* DNS namespace, along with any intermediate nodes between zones. |
|
* A ZoneNode that represents a zone may be "populated" with a |
|
* NameNode tree containing the zone's contents. |
|
* |
|
* <p> A populated zone's contents will be flagged as having expired after |
|
* the time specified by the minimum TTL value in the zone's SOA record. |
|
* |
|
* <p> Since zone cuts aren't directly modeled by a tree of ZoneNodes, |
|
* ZoneNode.isZoneCut() always returns false. |
|
* |
|
* <p> The synchronization strategy is documented in DnsContext.java. |
|
* |
|
* <p> The zone's contents are accessed via a soft reference, so its |
|
* heap space may be reclaimed when necessary. The zone may be |
|
* repopulated later. |
|
* |
|
* @author Scott Seligman |
|
*/ |
|
|
|
|
|
class ZoneNode extends NameNode { |
|
|
|
private SoftReference<NameNode> contentsRef = null; |
|
private long serialNumber = -1; |
|
private Date expiration = null; |
|
|
|
ZoneNode(String label) { |
|
super(label); |
|
} |
|
|
|
protected NameNode newNameNode(String label) { |
|
return new ZoneNode(label); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized void depopulate() { |
|
contentsRef = null; |
|
serialNumber = -1; |
|
} |
|
|
|
|
|
|
|
*/ |
|
synchronized boolean isPopulated() { |
|
return (getContents() != null); |
|
} |
|
|
|
|
|
|
|
*/ |
|
synchronized NameNode getContents() { |
|
return (contentsRef != null) |
|
? contentsRef.get() |
|
: null; |
|
} |
|
|
|
|
|
|
|
*/ |
|
synchronized boolean isExpired() { |
|
return ((expiration != null) && expiration.before(new Date())); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
ZoneNode getDeepestPopulated(DnsName fqdn) { |
|
ZoneNode znode = this; |
|
ZoneNode popNode = isPopulated() ? this : null; |
|
for (int i = 1; i < fqdn.size(); i++) { |
|
znode = (ZoneNode) znode.get(fqdn.getKey(i)); |
|
if (znode == null) { |
|
break; |
|
} else if (znode.isPopulated()) { |
|
popNode = znode; |
|
} |
|
} |
|
return popNode; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
NameNode populate(DnsName zone, ResourceRecords rrs) { |
|
// assert zone.get(0).equals(""); // zone has root label |
|
// assert (zone.size() == (depth() + 1)); // +1 due to root label |
|
|
|
NameNode newContents = new NameNode(null); |
|
|
|
for (int i = 0; i < rrs.answer.size(); i++) { |
|
ResourceRecord rr = rrs.answer.elementAt(i); |
|
DnsName n = rr.getName(); |
|
|
|
// Ignore resource records whose names aren't within the zone's |
|
// domain. Also skip records of the zone's top node, since |
|
|
|
if ((n.size() > zone.size()) && n.startsWith(zone)) { |
|
NameNode nnode = newContents.add(n, zone.size()); |
|
if (rr.getType() == ResourceRecord.TYPE_NS) { |
|
nnode.setZoneCut(true); |
|
} |
|
} |
|
} |
|
|
|
ResourceRecord soa = rrs.answer.firstElement(); |
|
synchronized (this) { |
|
contentsRef = new SoftReference<NameNode>(newContents); |
|
serialNumber = getSerialNumber(soa); |
|
setExpiration(getMinimumTtl(soa)); |
|
return newContents; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void setExpiration(long secsToExpiration) { |
|
expiration = new Date(System.currentTimeMillis() + |
|
1000 * secsToExpiration); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static long getMinimumTtl(ResourceRecord soa) { |
|
String rdata = (String) soa.getRdata(); |
|
int pos = rdata.lastIndexOf(' ') + 1; |
|
return Long.parseLong(rdata.substring(pos)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
int compareSerialNumberTo(ResourceRecord soa) { |
|
|
|
return ResourceRecord.compareSerialNumbers(serialNumber, |
|
getSerialNumber(soa)); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static long getSerialNumber(ResourceRecord soa) { |
|
String rdata = (String) soa.getRdata(); |
|
|
|
// An SOA record ends with: serial refresh retry expire minimum. |
|
// Set "beg" to the space before serial, and "end" to the space after. |
|
|
|
int beg = rdata.length(); |
|
int end = -1; |
|
for (int i = 0; i < 5; i++) { |
|
end = beg; |
|
beg = rdata.lastIndexOf(' ', end - 1); |
|
} |
|
return Long.parseLong(rdata.substring(beg + 1, end)); |
|
} |
|
} |