38 * NameNode tree containing the zone's contents. 39 * 40 * <p> A populated zone's contents will be flagged as having expired after 41 * the time specified by the minimum TTL value in the zone's SOA record. 42 * 43 * <p> Since zone cuts aren't directly modeled by a tree of ZoneNodes, 44 * ZoneNode.isZoneCut() always returns false. 45 * 46 * <p> The synchronization strategy is documented in DnsContext.java. 47 * 48 * <p> The zone's contents are accessed via a soft reference, so its 49 * heap space may be reclaimed when necessary. The zone may be 50 * repopulated later. 51 * 52 * @author Scott Seligman 53 */ 54 55 56 class ZoneNode extends NameNode { 57 58 private SoftReference contentsRef = null; // the zone's namespace 59 private long serialNumber = -1; // the zone data's serial number 60 private Date expiration = null; // time when the zone's data expires 61 62 ZoneNode(String label) { 63 super(label); 64 } 65 66 protected NameNode newNameNode(String label) { 67 return new ZoneNode(label); 68 } 69 70 /* 71 * Clears the contents of this node. If the node was flagged as 72 * expired, it remains so. 73 */ 74 synchronized void depopulate() { 75 contentsRef = null; 76 serialNumber = -1; 77 } 78 79 /* 80 * Is this node currently populated? 81 */ 82 synchronized boolean isPopulated() { 83 return (getContents() != null); 84 } 85 86 /* 87 * Returns the zone's contents, or null if the zone is not populated. 88 */ 89 synchronized NameNode getContents() { 90 return (contentsRef != null) 91 ? (NameNode) contentsRef.get() 92 : null; 93 } 94 95 /* 96 * Has this zone's data expired? 97 */ 98 synchronized boolean isExpired() { 99 return ((expiration != null) && expiration.before(new Date())); 100 } 101 102 /* 103 * Returns the deepest populated zone on the path specified by a 104 * fully-qualified domain name, or null if there is no populated 105 * zone on that path. Note that a node may be depopulated after 106 * being returned. 107 */ 108 ZoneNode getDeepestPopulated(DnsName fqdn) { 109 ZoneNode znode = this; 110 ZoneNode popNode = isPopulated() ? this : null; 111 for (int i = 1; i < fqdn.size(); i++) { // "i=1" to skip root label 113 if (znode == null) { 114 break; 115 } else if (znode.isPopulated()) { 116 popNode = znode; 117 } 118 } 119 return popNode; 120 } 121 122 /* 123 * Populates (or repopulates) a zone given its own fully-qualified 124 * name and its resource records. Returns the zone's new contents. 125 */ 126 NameNode populate(DnsName zone, ResourceRecords rrs) { 127 // assert zone.get(0).equals(""); // zone has root label 128 // assert (zone.size() == (depth() + 1)); // +1 due to root label 129 130 NameNode newContents = new NameNode(null); 131 132 for (int i = 0; i < rrs.answer.size(); i++) { 133 ResourceRecord rr = (ResourceRecord) rrs.answer.elementAt(i); 134 DnsName n = rr.getName(); 135 136 // Ignore resource records whose names aren't within the zone's 137 // domain. Also skip records of the zone's top node, since 138 // the zone's root NameNode is already in place. 139 if ((n.size() > zone.size()) && n.startsWith(zone)) { 140 NameNode nnode = newContents.add(n, zone.size()); 141 if (rr.getType() == ResourceRecord.TYPE_NS) { 142 nnode.setZoneCut(true); 143 } 144 } 145 } 146 // The zone's SOA record is the first record in the answer section. 147 ResourceRecord soa = (ResourceRecord) rrs.answer.firstElement(); 148 synchronized (this) { 149 contentsRef = new SoftReference(newContents); 150 serialNumber = getSerialNumber(soa); 151 setExpiration(getMinimumTtl(soa)); 152 return newContents; 153 } 154 } 155 156 /* 157 * Set this zone's data to expire in <tt>secsToExpiration</tt> seconds. 158 */ 159 private void setExpiration(long secsToExpiration) { 160 expiration = new Date(System.currentTimeMillis() + 161 1000 * secsToExpiration); 162 } 163 164 /* 165 * Returns an SOA record's minimum TTL field. 166 */ 167 private static long getMinimumTtl(ResourceRecord soa) { 168 String rdata = (String) soa.getRdata(); 169 int pos = rdata.lastIndexOf(' ') + 1; | 38 * NameNode tree containing the zone's contents. 39 * 40 * <p> A populated zone's contents will be flagged as having expired after 41 * the time specified by the minimum TTL value in the zone's SOA record. 42 * 43 * <p> Since zone cuts aren't directly modeled by a tree of ZoneNodes, 44 * ZoneNode.isZoneCut() always returns false. 45 * 46 * <p> The synchronization strategy is documented in DnsContext.java. 47 * 48 * <p> The zone's contents are accessed via a soft reference, so its 49 * heap space may be reclaimed when necessary. The zone may be 50 * repopulated later. 51 * 52 * @author Scott Seligman 53 */ 54 55 56 class ZoneNode extends NameNode { 57 58 private SoftReference<NameNode> contentsRef = null; // the zone's namespace 59 private long serialNumber = -1; // the zone data's serial number 60 private Date expiration = null; // time when the zone's data expires 61 62 ZoneNode(String label) { 63 super(label); 64 } 65 66 protected NameNode newNameNode(String label) { 67 return new ZoneNode(label); 68 } 69 70 /* 71 * Clears the contents of this node. If the node was flagged as 72 * expired, it remains so. 73 */ 74 synchronized void depopulate() { 75 contentsRef = null; 76 serialNumber = -1; 77 } 78 79 /* 80 * Is this node currently populated? 81 */ 82 synchronized boolean isPopulated() { 83 return (getContents() != null); 84 } 85 86 /* 87 * Returns the zone's contents, or null if the zone is not populated. 88 */ 89 synchronized NameNode getContents() { 90 return (contentsRef != null) 91 ? contentsRef.get() 92 : null; 93 } 94 95 /* 96 * Has this zone's data expired? 97 */ 98 synchronized boolean isExpired() { 99 return ((expiration != null) && expiration.before(new Date())); 100 } 101 102 /* 103 * Returns the deepest populated zone on the path specified by a 104 * fully-qualified domain name, or null if there is no populated 105 * zone on that path. Note that a node may be depopulated after 106 * being returned. 107 */ 108 ZoneNode getDeepestPopulated(DnsName fqdn) { 109 ZoneNode znode = this; 110 ZoneNode popNode = isPopulated() ? this : null; 111 for (int i = 1; i < fqdn.size(); i++) { // "i=1" to skip root label 113 if (znode == null) { 114 break; 115 } else if (znode.isPopulated()) { 116 popNode = znode; 117 } 118 } 119 return popNode; 120 } 121 122 /* 123 * Populates (or repopulates) a zone given its own fully-qualified 124 * name and its resource records. Returns the zone's new contents. 125 */ 126 NameNode populate(DnsName zone, ResourceRecords rrs) { 127 // assert zone.get(0).equals(""); // zone has root label 128 // assert (zone.size() == (depth() + 1)); // +1 due to root label 129 130 NameNode newContents = new NameNode(null); 131 132 for (int i = 0; i < rrs.answer.size(); i++) { 133 ResourceRecord rr = rrs.answer.elementAt(i); 134 DnsName n = rr.getName(); 135 136 // Ignore resource records whose names aren't within the zone's 137 // domain. Also skip records of the zone's top node, since 138 // the zone's root NameNode is already in place. 139 if ((n.size() > zone.size()) && n.startsWith(zone)) { 140 NameNode nnode = newContents.add(n, zone.size()); 141 if (rr.getType() == ResourceRecord.TYPE_NS) { 142 nnode.setZoneCut(true); 143 } 144 } 145 } 146 // The zone's SOA record is the first record in the answer section. 147 ResourceRecord soa = rrs.answer.firstElement(); 148 synchronized (this) { 149 contentsRef = new SoftReference<NameNode>(newContents); 150 serialNumber = getSerialNumber(soa); 151 setExpiration(getMinimumTtl(soa)); 152 return newContents; 153 } 154 } 155 156 /* 157 * Set this zone's data to expire in <tt>secsToExpiration</tt> seconds. 158 */ 159 private void setExpiration(long secsToExpiration) { 160 expiration = new Date(System.currentTimeMillis() + 161 1000 * secsToExpiration); 162 } 163 164 /* 165 * Returns an SOA record's minimum TTL field. 166 */ 167 private static long getMinimumTtl(ResourceRecord soa) { 168 String rdata = (String) soa.getRdata(); 169 int pos = rdata.lastIndexOf(' ') + 1; |