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: package org.apache.harmony.jndi.provider.dns;
020:
021: import java.util.Enumeration;
022: import java.util.Hashtable;
023: import java.util.Vector;
024:
025: import org.apache.harmony.jndi.internal.nls.Messages;
026:
027: /**
028: * Represents DNS resolver's SLIST - the structure to keep the collected
029: * information about active DNS servers and zones they contain information
030: * about.
031: *
032: * @see RFC 1034 TODO some methods can be optimized
033: */
034: class SList {
035:
036: public static int NETWORK_FAILURE = Integer.MAX_VALUE - 3;
037:
038: public static int TIMEOUT = Integer.MAX_VALUE - 2;
039:
040: public static int SERVER_FAILURE = Integer.MAX_VALUE - 1;
041:
042: public static int UNKNOWN = 0;
043:
044: // Hash with vectors; one vector of server entries per zone
045: private Hashtable<String, Vector<Entry>> zones;
046:
047: // the array with known DNS servers information
048: private Vector<Server> servers;
049:
050: /**
051: * @see #getInstance()
052: */
053: private SList() {
054: zones = new Hashtable<String, Vector<Entry>>();
055: servers = new Vector<Server>();
056: }
057:
058: private static SList instance = new SList();
059:
060: /**
061: * <code>SList</code> is a singleton class.
062: *
063: * @return instance of <code>SList</code>
064: */
065: static SList getInstance() {
066: return instance;
067: }
068:
069: /**
070: * Updates existent SLIST entry or creates a new one. S-List will be sorted
071: * according the response time. Entries with bigger response will be placed
072: * father from the beginning of the list.
073: *
074: * @param zone
075: * the name of DNS zone
076: * @param server
077: * the server that is known to have the information about given
078: * zone
079: * @param responseTime
080: * response time for server for this particular DNS zone
081: */
082: void updateEntry(String zone, Server server, int responseTime) {
083: String normZoneName = ProviderMgr.normalizeName(zone);
084: Vector<Entry> vect;
085: Entry entryToAdd = new Entry(normZoneName,
086: getServerNum(server), responseTime);
087:
088: synchronized (zones) {
089: vect = zones.get(ProviderMgr.normalizeName(normZoneName));
090: if (vect == null) {
091: vect = new Vector<Entry>();
092: vect.addElement(entryToAdd);
093: zones.put(normZoneName, vect);
094: } else {
095: boolean added = false;
096:
097: // delete previous occurrence of given server
098: for (int i = 0; i < vect.size(); i++) {
099: Entry curEntry = vect.elementAt(i);
100:
101: if (server.equals(serverAtNum(curEntry
102: .getServerNum()))) {
103: vect.removeElementAt(i);
104: break;
105: }
106: }
107:
108: // and insert a new one with updated response time
109: for (int i = 0; i < vect.size(); i++) {
110: Entry curEntry = vect.elementAt(i);
111:
112: if (responseTime < curEntry.getResponseTime()) {
113: vect.insertElementAt(entryToAdd, i);
114: added = true;
115: break;
116: }
117: }
118: // append to the end of list if not found
119: if (!added) {
120: vect.addElement(entryToAdd);
121: }
122: }
123: } // synchronized block
124: }
125:
126: /**
127: * Returns the best guess about that DNS server should be chosen to send the
128: * request concerning the particular DNS zone.
129: *
130: * @param zone
131: * the name of DNS zone
132: * @return best guess - a <code>SList.Server</code> object;
133: * <code>null</code> if the information is not found
134: */
135: Server getBestGuess(String zone,
136: Hashtable<Server, ?> serversToIgnore) {
137: Vector<Entry> vect;
138:
139: synchronized (zones) {
140: vect = zones.get(ProviderMgr.normalizeName(zone));
141: if (vect != null && vect.size() > 0) {
142: for (int i = 0; i < vect.size(); i++) {
143: Entry entry = vect.elementAt(i);
144:
145: if (serversToIgnore != null) {
146: if (serversToIgnore.get(serverAtNum(entry
147: .getServerNum())) != null) {
148: continue;
149: }
150: }
151: return serverAtNum(entry.getServerNum());
152: }
153: }
154: }
155: return null;
156: }
157:
158: /**
159: * Removes occurrence of given server related to given zone from the SLIST.
160: *
161: * @param zone
162: * DNS zone
163: * @param server
164: * the server to remove
165: */
166: void dropServer(String zone, Server server) {
167: Vector<Entry> vect;
168:
169: synchronized (zones) {
170: vect = zones.get(ProviderMgr.normalizeName(zone));
171: if (vect != null) {
172: for (int i = 0; i < vect.size(); i++) {
173: Entry entry = vect.elementAt(i);
174:
175: if (server
176: .equals(serverAtNum(entry.getServerNum()))) {
177: vect.removeElementAt(i);
178: break;
179: }
180: }
181: }
182: }
183: }
184:
185: /**
186: * @param zone
187: * the name of zone
188: * @param server
189: * DNS server
190: * @return <code>true</code> if SList has information about specified
191: * server & zone combination; <code>false</code> otherwise
192: */
193: boolean hasServer(String zone, Server server) {
194: Vector<Entry> vect;
195:
196: synchronized (zones) {
197: vect = zones.get(ProviderMgr.normalizeName(zone));
198: if (vect != null) {
199: for (int i = 0; i < vect.size(); i++) {
200: Entry entry = vect.elementAt(i);
201:
202: if (server
203: .equals(serverAtNum(entry.getServerNum()))) {
204: return true;
205: }
206: }
207: }
208: }
209: return false;
210: }
211:
212: /**
213: * @param zone
214: * the name DNS zone
215: * @param srvName
216: * the name of the server
217: * @param srvPort
218: * the port of the server
219: * @return <code>Server</code> object with specified attributes
220: */
221: Server getServerByName(String zone, String name, int port) {
222: Vector<Entry> vect;
223:
224: synchronized (zones) {
225: vect = zones.get(ProviderMgr.normalizeName(zone));
226: if (vect != null) {
227: for (int i = 0; i < vect.size(); i++) {
228: Entry entry = vect.elementAt(i);
229:
230: if (ProviderMgr.namesAreEqual(name, serverAtNum(
231: entry.getServerNum()).getName())
232: && port == serverAtNum(entry.getServerNum())
233: .getPort()) {
234: return serverAtNum(entry.getServerNum());
235: }
236: }
237: }
238: }
239: return null;
240: }
241:
242: /**
243: * @param zone
244: * name of DNS zone
245: * @param srvIP
246: * IPv4 address of server
247: * @param srvPort
248: * port on server
249: * @return <code>Server</code> object with specified attributes
250: */
251: Server getServerByIP(String zone, String ip, int port) {
252: Vector<Entry> vect;
253:
254: synchronized (zones) {
255: vect = zones.get(ProviderMgr.normalizeName(zone));
256: if (vect != null) {
257: for (int i = 0; i < vect.size(); i++) {
258: Entry entry = vect.elementAt(i);
259:
260: if (ip.equals(serverAtNum(entry.getServerNum())
261: .getIP())
262: && port == serverAtNum(entry.getServerNum())
263: .getPort()) {
264: return serverAtNum(entry.getServerNum());
265: }
266: }
267: }
268: }
269: return null;
270: }
271:
272: /**
273: * @param zone
274: * the name of DNS zone to query SLIST with
275: * @param server
276: * the server to compare with
277: * @return first <code>Server</code> object from SLIST that equals to
278: * specified server in terms of <code>equals()</code> method;
279: * <code>null</code> if not found.
280: * @see SList.Server#equals(SList.Server)
281: */
282: Server getServerByServer(String zone, Server server) {
283: Vector<Entry> vect;
284:
285: synchronized (zones) {
286: vect = zones.get(ProviderMgr.normalizeName(zone));
287:
288: if (vect != null) {
289: for (int i = 0; i < vect.size(); i++) {
290: Entry entry = vect.elementAt(i);
291: if (server
292: .equals(serverAtNum(entry.getServerNum()))) {
293: return serverAtNum(entry.getServerNum());
294: }
295: }
296: }
297: }
298: return null;
299: }
300:
301: /**
302: * Clears the SLIST.
303: */
304: void clear() {
305: synchronized (zones) {
306: zones = new Hashtable<String, Vector<Entry>>();
307: }
308: }
309:
310: // --- managing local list of servers ---
311:
312: // since the list of servers is add-only entity a write synchronization
313: // should be enough
314:
315: /**
316: * @return number of given server in the internal array of servers; add the
317: * server if not found
318: */
319: private int getServerNum(Server server) {
320: if (servers.contains(server)) {
321: return servers.indexOf(server);
322: }
323: synchronized (servers) {
324: servers.addElement(server);
325: return servers.size() - 1;
326: }
327: }
328:
329: /**
330: * @param num
331: * internal number of server
332: * @return <code>Server</code> object found at specified index
333: */
334: private Server serverAtNum(int num) {
335: if (num < servers.size()) {
336: return servers.elementAt(num);
337: }
338: return null;
339: }
340:
341: /**
342: * Checks if given server is present in the internal list of known servers.
343: *
344: * @param hostname
345: * host name of server
346: * @return <code>true</code> or <code>false</code>
347: */
348: boolean hasServer(String hostname) {
349: return servers.contains(new Server(hostname, null,
350: ProviderConstants.DEFAULT_DNS_PORT));
351: }
352:
353: /**
354: * Returns all occurrences of server with specified
355: *
356: * @param name
357: * hostname
358: * @return found server object or <code>null</code> if not found
359: */
360: Enumeration<Server> getServersByName(String name) {
361: Vector<Server> result = new Vector<Server>();
362:
363: if (name == null) {
364: // jndi.34=hostname is null
365: throw new NullPointerException(Messages
366: .getString("jndi.34")); //$NON-NLS-1$
367: }
368: for (int i = 0; i < servers.size(); i++) {
369: Server curServ = servers.get(i);
370:
371: if (curServ.getName() != null
372: && ProviderMgr.namesAreEqual(name, curServ
373: .getName())) {
374: result.addElement(curServ);
375: }
376: }
377: return result.elements();
378: }
379:
380: /**
381: * Add IP information of server in list. Affects only servers with IP set to
382: * <code>null</code>.
383: *
384: * @param hostname
385: * hostname of server
386: * @param newIP
387: * new IP
388: */
389: void setServerIP(String hostname, String newIP) {
390: String nameNorm = ProviderMgr.normalizeName(hostname);
391:
392: for (int i = 0; i < servers.size(); i++) {
393: SList.Server serv = servers.elementAt(i);
394:
395: if (nameNorm.equals(serv.getName()) && serv.getIP() == null) {
396: serv.setIP(newIP);
397: break;
398: }
399: }
400: }
401:
402: // --- additional classes ---
403:
404: /**
405: * Represents an SLIST entry.
406: */
407: static class Entry {
408:
409: private String zoneName;
410:
411: private int serverNum;
412:
413: private int responseTime;
414:
415: /**
416: * Creates new SLIST entry.
417: *
418: * @param zoneName
419: * @param server
420: * @param respTime
421: */
422: public Entry(String zoneName, int serverNum, int respTime) {
423: this .zoneName = zoneName;
424: this .serverNum = serverNum;
425: this .responseTime = respTime;
426: }
427:
428: /**
429: * @return Returns the responseTime.
430: */
431: public int getResponseTime() {
432: return responseTime;
433: }
434:
435: /**
436: * @param responseTime
437: * The responseTime to set.
438: */
439: public void setResponseTime(int responseTime) {
440: this .responseTime = responseTime;
441: }
442:
443: /**
444: * @return Returns the server.
445: */
446: public int getServerNum() {
447: return serverNum;
448: }
449:
450: /**
451: * @param server
452: * The server to set.
453: */
454: public void setServerNum(int serverNum) {
455: this .serverNum = serverNum;
456: }
457:
458: /**
459: * @return Returns the zoneName.
460: */
461: public String getZoneName() {
462: return zoneName;
463: }
464:
465: /**
466: * @param zoneName
467: * The zoneName to set.
468: */
469: public void setZoneName(String zoneName) {
470: this .zoneName = zoneName;
471: }
472: }
473:
474: /**
475: * Represents a DNS server.
476: */
477: static class Server {
478:
479: private String serverName;
480:
481: private String serverIP;
482:
483: private int serverPort;
484:
485: /**
486: * Constructs new <code>Server</code> object with given parameters.
487: *
488: * @param serverName
489: * the name of the server
490: * @param serverIP
491: * IP address of the server
492: * @param serverPort
493: * a port number
494: */
495: public Server(String serverName, String serverIP, int serverPort) {
496: this .serverName = ProviderMgr.normalizeName(serverName);
497: this .serverIP = serverIP;
498: this .serverPort = serverPort;
499: }
500:
501: /**
502: * Returns <code>true</code> if two servers are equal,
503: * <code>false</code> otherwise.
504: *
505: * @param obj
506: * a <code>Server</code> object to compare with
507: * @return <code>true</code> or <code>false</code>
508: */
509: @Override
510: public boolean equals(Object obj) {
511: SList.Server srv = null;
512:
513: if (!(obj instanceof SList.Server)) {
514: return false;
515: }
516: srv = (SList.Server) obj;
517: if (serverIP == null || srv.getIP() == null) {
518: if (this .getName() == null || srv.getName() == null) {
519: return false;
520: }
521: return ProviderMgr.namesAreEqual(this .getName(), srv
522: .getName())
523: && this .getPort() == srv.getPort();
524: }
525: return this .getIP().equals(srv.getIP())
526: && this .getPort() == srv.getPort();
527: }
528:
529: /**
530: * @return Returns the serverIP.
531: */
532: public String getIP() {
533: return serverIP;
534: }
535:
536: /**
537: * @return Returns the serverName.
538: */
539: public String getName() {
540: return serverName;
541: }
542:
543: /**
544: * @return Returns the serverPort.
545: */
546: public int getPort() {
547: return serverPort;
548: }
549:
550: /**
551: * @param serverIP
552: * The serverIP to set.
553: */
554: public void setIP(String serverIP) {
555: this .serverIP = serverIP;
556: }
557:
558: /**
559: * @param serverName
560: * The serverName to set.
561: */
562: public void setName(String serverName) {
563: this .serverName = ProviderMgr.normalizeName(serverName);
564: }
565:
566: /**
567: * @param serverPort
568: * The serverPort to set.
569: */
570: public void setPort(int serverPort) {
571: this .serverPort = serverPort;
572: }
573:
574: @Override
575: public String toString() {
576: if (this .serverName != null) {
577: return serverName + ":" + serverPort; //$NON-NLS-1$
578: }
579: return serverIP + ":" + serverPort; //$NON-NLS-1$
580: }
581: }
582:
583: }
|