| /** |
| * Copyright 2003-2005 Arthur van Hoff, Rick Blair |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.activemq.jmdns; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.logging.Logger; |
| |
| /** |
| * A table of DNS entries. This is a hash table which |
| * can handle multiple entries with the same name. |
| * <p/> |
| * Storing multiple entries with the same name is implemented using a |
| * linked list of <code>CacheNode</code>'s. |
| * <p/> |
| * The current implementation of the API of DNSCache does expose the |
| * cache nodes to clients. Clients must explicitly deal with the nodes |
| * when iterating over entries in the cache. Here's how to iterate over |
| * all entries in the cache: |
| * <pre> |
| * for (Iterator i=dnscache.iterator(); i.hasNext(); ) { |
| * for (DNSCache.CacheNode n = (DNSCache.CacheNode) i.next(); n != null; n.next()) { |
| * DNSEntry entry = n.getValue(); |
| * ...do something with entry... |
| * } |
| * } |
| * </pre> |
| * <p/> |
| * And here's how to iterate over all entries having a given name: |
| * <pre> |
| * for (DNSCache.CacheNode n = (DNSCache.CacheNode) dnscache.find(name); n != null; n.next()) { |
| * DNSEntry entry = n.getValue(); |
| * ...do something with entry... |
| * } |
| * </pre> |
| * |
| * @version %I%, %G% |
| * @author Arthur van Hoff, Werner Randelshofer, Rick Blair |
| */ |
| class DNSCache |
| { |
| private static Logger logger = Logger.getLogger(DNSCache.class.toString()); |
| // Implementation note: |
| // We might completely hide the existence of CacheNode's in a future version |
| // of DNSCache. But this will require to implement two (inner) classes for |
| // the iterators that will be returned by method <code>iterator()</code> and |
| // method <code>find(name)</code>. |
| // Since DNSCache is not a public class, it does not seem worth the effort |
| // to clean its API up that much. |
| |
| // [PJYF Oct 15 2004] This should implements Collections that would be amuch cleaner implementation |
| |
| /** |
| * The number of DNSEntry's in the cache. |
| */ |
| private int size; |
| |
| /** |
| * The hashtable used internally to store the entries of the cache. |
| * Keys are instances of String. The String contains an unqualified service |
| * name. |
| * Values are linked lists of CacheNode instances. |
| */ |
| private HashMap hashtable; |
| |
| /** |
| * Cache nodes are used to implement storage of multiple DNSEntry's of the |
| * same name in the cache. |
| */ |
| public static class CacheNode |
| { |
| private static Logger logger = Logger.getLogger(CacheNode.class.toString()); |
| private DNSEntry value; |
| private CacheNode next; |
| |
| public CacheNode(DNSEntry value) |
| { |
| this.value = value; |
| } |
| |
| public CacheNode next() |
| { |
| return next; |
| } |
| |
| public DNSEntry getValue() |
| { |
| return value; |
| } |
| } |
| |
| |
| /** |
| * Create a table with a given initial size. |
| */ |
| public DNSCache(final int size) |
| { |
| hashtable = new HashMap(size); |
| } |
| |
| /** |
| * Clears the cache. |
| */ |
| public synchronized void clear() |
| { |
| hashtable.clear(); |
| size = 0; |
| } |
| |
| /** |
| * Adds an entry to the table. |
| */ |
| public synchronized void add(final DNSEntry entry) |
| { |
| //logger.log("DNSCache.add("+entry.getName()+")"); |
| CacheNode newValue = new CacheNode(entry); |
| CacheNode node = (CacheNode) hashtable.get(entry.getName()); |
| if (node == null) |
| { |
| hashtable.put(entry.getName(), newValue); |
| } |
| else |
| { |
| newValue.next = node.next; |
| node.next = newValue; |
| } |
| size++; |
| } |
| |
| /** |
| * Remove a specific entry from the table. Returns true if the |
| * entry was found. |
| */ |
| public synchronized boolean remove(DNSEntry entry) |
| { |
| CacheNode node = (CacheNode) hashtable.get(entry.getName()); |
| if (node != null) |
| { |
| if (node.value == entry) |
| { |
| if (node.next == null) |
| { |
| hashtable.remove(entry.getName()); |
| } |
| else |
| { |
| hashtable.put(entry.getName(), node.next); |
| } |
| size--; |
| return true; |
| } |
| |
| CacheNode previous = node; |
| node = node.next; |
| while (node != null) |
| { |
| if (node.value == entry) |
| { |
| previous.next = node.next; |
| size--; |
| return true; |
| } |
| previous = node; |
| node = node.next; |
| } |
| ; |
| } |
| return false; |
| } |
| |
| /** |
| * Get a matching DNS entry from the table (using equals). |
| * Returns the entry that was found. |
| */ |
| public synchronized DNSEntry get(DNSEntry entry) |
| { |
| for (CacheNode node = find(entry.getName()); node != null; node = node.next) |
| { |
| if (node.value.equals(entry)) |
| { |
| return node.value; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get a matching DNS entry from the table. |
| */ |
| public synchronized DNSEntry get(String name, int type, int clazz) |
| { |
| for (CacheNode node = find(name); node != null; node = node.next) |
| { |
| if (node.value.type == type && node.value.clazz == clazz) |
| { |
| return node.value; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Iterates over all cache nodes. |
| * The iterator returns instances of DNSCache.CacheNode. |
| * Each instance returned is the first node of a linked list. |
| * To retrieve all entries, one must iterate over this linked list. See |
| * code snippets in the header of the class. |
| */ |
| public Iterator iterator() |
| { |
| return Collections.unmodifiableCollection(hashtable.values()).iterator(); |
| } |
| |
| /** |
| * Iterate only over items with matching name. |
| * Returns an instance of DNSCache.CacheNode or null. |
| * If an instance is returned, it is the first node of a linked list. |
| * To retrieve all entries, one must iterate over this linked list. |
| */ |
| public synchronized CacheNode find(String name) |
| { |
| return (CacheNode) hashtable.get(name); |
| } |
| |
| /** |
| * List all entries for debugging. |
| */ |
| public synchronized void print() |
| { |
| for (Iterator i = iterator(); i.hasNext();) |
| { |
| for (CacheNode n = (CacheNode) i.next(); n != null; n = n.next) |
| { |
| System.out.println(n.value); |
| } |
| } |
| } |
| |
| public synchronized String toString() |
| { |
| StringBuffer aLog = new StringBuffer(); |
| aLog.append("\t---- cache ----"); |
| for (Iterator i = iterator(); i.hasNext();) |
| { |
| for (CacheNode n = (CacheNode) i.next(); n != null; n = n.next) |
| { |
| aLog.append("\n\t\t" + n.value); |
| } |
| } |
| return aLog.toString(); |
| } |
| |
| } |