001: /* Licensed to the Apache Software Foundation (ASF) under one or more
002: * contributor license agreements. See the NOTICE file distributed with
003: * this work for additional information regarding copyright ownership.
004: * The ASF licenses this file to You under the Apache License, Version 2.0
005: * (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package java.net;
018:
019: import java.security.AccessController;
020: import java.util.LinkedHashMap;
021: import java.util.Map;
022:
023: import org.apache.harmony.luni.util.PriviAction;
024:
025: /**
026: * This class is used to manage the negative name lookup cache.
027: */
028: class NegativeCache<K, V> extends LinkedHashMap<K, V> {
029:
030: private static final long serialVersionUID = 1L;
031:
032: static NegativeCache<String, NegCacheElement> negCache;
033:
034: // maximum number of entries in the cache
035: static final int MAX_NEGATIVE_ENTRIES = 5;
036:
037: // the loading for the cache
038: static final float LOADING = 0.75F;
039:
040: /**
041: * Answers the hostname for the cache element
042: *
043: * @return hostName name of the host on which the lookup failed
044: */
045: NegativeCache(int initialCapacity, float loadFactor,
046: boolean accessOrder) {
047: super (initialCapacity, loadFactor, accessOrder);
048: }
049:
050: /**
051: * Answers if we should remove the Eldest entry. We remove the eldest entry
052: * if the size has grown beyond the maximum size allowed for the cache. We
053: * create the LinkedHashMap such that this deletes the least recently used
054: * entry
055: *
056: * @param eldest
057: * the map entry which will be deleted if we return true
058: */
059: @Override
060: protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
061: return size() > MAX_NEGATIVE_ENTRIES;
062: }
063:
064: /**
065: * Adds the host name and the corresponding name lookup fail message to the
066: * cache
067: *
068: * @param hostName
069: * the name of the host for which the lookup failed
070: * @param failedMessage
071: * the message returned when we failed the lookup
072: */
073: static void put(String hostName, String failedMessage) {
074: checkCacheExists();
075: negCache.put(hostName, new NegCacheElement(failedMessage));
076: }
077:
078: /**
079: * Answers the message that occurred when we failed to lookup the host if
080: * such a failure is within the cache and the entry has not yet expired
081: *
082: * @param hostName
083: * the name of the host for which we are looking for an entry
084: * @return the message which was returned when the host failed to be looked
085: * up if there is still a valid entry within the cache
086: */
087: static String getFailedMessage(String hostName) {
088: checkCacheExists();
089: NegCacheElement element = negCache.get(hostName);
090: if (element != null) {
091: // check if element is still valid
092: String ttlValue = AccessController
093: .doPrivileged(new PriviAction<String>(
094: "networkaddress.cache.negative.ttl")); //$NON-NLS-1$
095: int ttl = 10;
096: try {
097: if (ttlValue != null) {
098: ttl = Integer.decode(ttlValue).intValue();
099: }
100: } catch (NumberFormatException e) {
101: }
102: if (ttl == 0) {
103: negCache.clear();
104: element = null;
105: } else if (ttl != -1) {
106: if (element.timeAdded + (ttl * 1000) < System
107: .currentTimeMillis()) {
108: // remove the element from the cache and return null
109: negCache.remove(hostName);
110: element = null;
111: }
112: }
113: }
114: if (element != null) {
115: return element.hostName();
116: }
117: return null;
118: }
119:
120: /**
121: * This method checks if we have created the cache and if not creates it
122: */
123: static void checkCacheExists() {
124: if (negCache == null) {
125: /*
126: * Create with the access order set so ordering is based on when the
127: * entries were last accessed. We make the default cache size one
128: * greater than the maximum number of entries as we will grow to one
129: * larger and then delete the LRU entry
130: */
131: negCache = new NegativeCache<String, NegCacheElement>(
132: MAX_NEGATIVE_ENTRIES + 1, LOADING, true);
133: }
134: }
135: }
|