001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Alexei Y. Zakharov
021: * @version $Revision: 1.1.2.4 $
022: */package org.apache.harmony.jndi.provider.dns;
023:
024: import java.util.Enumeration;
025: import java.util.HashMap;
026: import java.util.Vector;
027:
028: /**
029: * A cache for received resource records. Common for all active resolvers.
030: *
031: * TODO handling of records with TTL set to 0; should not be cached.
032: */
033: class ResolverCache {
034:
035: /** keys - zone & host names; values - vectors with RRs */
036: HashMap<String, Vector<CacheEntry>> names = new HashMap<String, Vector<CacheEntry>>();
037:
038: /**
039: * Since <code>ResolverCache</code> is singleton class its constructor
040: * should be hidden.
041: */
042: private ResolverCache() {
043: names = new HashMap<String, Vector<CacheEntry>>();
044: }
045:
046: private static ResolverCache instance = null;
047:
048: /**
049: * <code>ResolverCache</code> is a singleton class.
050: *
051: * @return active instance of <code>ResolverCache</code>
052: */
053: static ResolverCache getInstance() {
054: if (instance == null) {
055: instance = new ResolverCache();
056: }
057: return instance;
058: }
059:
060: /**
061: * Looks through the cache and returns all suitable resource records
062: *
063: * @param question
064: * a question record that determines which records we want to get
065: * from the cache
066: * @return Enumeration of found Resource Records.
067: */
068: synchronized Enumeration<ResourceRecord> get(QuestionRecord question) {
069: String name = question.getQName().toLowerCase();
070: Vector<CacheEntry> vect = names.get(name);
071: int qClass = question.getQClass();
072: int qType = question.getQType();
073: Vector<ResourceRecord> resVect = new Vector<ResourceRecord>();
074:
075: if (vect != null) {
076: for (int i = 0; i < vect.size(); i++) {
077: CacheEntry curEntry = vect.elementAt(i);
078: ResourceRecord curRR = curEntry.getRR();
079:
080: if (curEntry.getBestBefore() < System
081: .currentTimeMillis()) {
082: // the record is out of date
083: vect.removeElementAt(i--);
084: continue;
085: }
086: if (qClass == ProviderConstants.ANY_QCLASS
087: || qClass != curRR.getRRClass()) {
088: continue;
089: }
090: if (qType == ProviderConstants.ANY_QTYPE
091: || qType != curRR.getRRType()) {
092: continue;
093: }
094: resVect.addElement(curRR);
095: }
096: }
097: return resVect.elements();
098: }
099:
100: /**
101: * Puts element into the cache. Doesn't put records with zero TTLs. Doesn't
102: * put records with bad TTLs.
103: *
104: * @param record
105: * a resource record to insert
106: */
107: synchronized void put(ResourceRecord record) {
108: String name = record.getName().toLowerCase();
109: Vector<CacheEntry> vect = names.get(name);
110: long curTime = System.currentTimeMillis();
111: CacheEntry entry = null;
112:
113: if (vect == null) {
114: vect = new Vector<CacheEntry>();
115: names.put(name, vect);
116: }
117: // TTL should be between 0 and 2^31; if greater - should be set to 0
118: // See RFC 2181 point 8
119: if (record.getTtl() >> 31 != 0) {
120: record.setTtl(0);
121: }
122: // skip records with wildcards in names or with zero TTL
123: if (record.getTtl() > 0
124: && (record.getName().indexOf('*') == -1)) {
125: entry = new CacheEntry(record, curTime + record.getTtl());
126: // remove old occurrence if any
127: for (int i = 0; i < vect.size(); i++) {
128: CacheEntry exEntry = vect.elementAt(i);
129: ResourceRecord exRec = exEntry.rr;
130:
131: if (ProviderMgr.namesAreEqual(record.getName(), exRec
132: .getName())
133: && record.getRRClass() == exRec.getRRClass()
134: && record.getRRType() == exRec.getRRType()) {
135: if (record.getRData() != null
136: && exRec.getRData() != null
137: && record.getRData().equals(
138: exRec.getRData())) {
139: vect.remove(i);
140: break;
141: }
142: }
143: }
144: vect.addElement(entry);
145: }
146: }
147:
148: /**
149: * Removes all cached entries.
150: */
151: synchronized void clear() {
152: names = new HashMap<String, Vector<CacheEntry>>();
153: }
154:
155: /**
156: * Represents SLIST cache entry.
157: */
158: static class CacheEntry {
159:
160: private ResourceRecord rr;
161:
162: private long bestBefore;
163:
164: /**
165: * Constructs new cache entry.
166: *
167: * @param rr
168: * Resource Record
169: * @param bestBefore
170: * best before (time in millis)
171: */
172: public CacheEntry(ResourceRecord rr, long bestBefore) {
173: this .rr = rr;
174: this .bestBefore = bestBefore;
175: }
176:
177: /**
178: * @return Returns the bestBefore.
179: */
180: public long getBestBefore() {
181: return bestBefore;
182: }
183:
184: /**
185: * @return Returns the Resource Record.
186: */
187: public ResourceRecord getRR() {
188: return rr;
189: }
190: }
191:
192: }
|