/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package netscape.ldap;
import java.util.*;
import java.io.*;
import netscape.ldap.client.*;
import netscape.ldap.util.*;
import java.util.zip.CRC32;
/**
* LDAPCache represents an in-memory cache that you can use
* to reduce the number of search requests sent to the LDAP server.
*
* * Each item in the cache represents a search request and * its results. Each item is uniquely identified by the * search criteria, which includes: *
* *
* * After a search request is cached, the results of any * subsequent search requests using the same criteria are * read from the cache. Note that if any part of the * criteria differs (for example, if a different DN is used * when binding to the server or if a different set of * attributes to be returned is specified), the search * request is sent to the server. *
* * When you create the cache, you specify the maximum amount * of time that an item can be kept in the cache. When an * item's age exceeds that time limit, the item is removed * from the cache. *
* * The cache also has a maximum size that you specify when * creating the cache. If adding a new item exceeds the * maximum size of the cache, the first entries in the cache * are removed to make enough space for the new item. *
*
* Finally, when creating the cache, you can specify a list
* of the base DNs in search requests that you want to cache.
* For example, if you specify o=Airius.com as
* a base DN to cache, your client caches search requests
* where the base DN is o=Airius.com.
*
*
* To specify that you want to use a cache for a particular
* LDAP session, call the setCache method of
* the LDAPConnection object that you are
* working with.
*
*
* All clones of an LDAPConnection object share
* the same LDAPCache object.
*
*
* Note that LDAPCache does not maintain consistency
* with the directory, so that cached search results may no longer be
* valid after a directory update. If the same application is performing
* both cached searches and directory updates, then the
* application should flush the corresponding cache entries after an update.
* To do this use the flushEntries method.
*
* * Also, note that search requests that return referrals are not cached. *
*
* The LDAPCache class includes methods for
* getting statistics (such as hit rates) from the cache and
* for flushing entries from the cache.
*
*
* @see netscape.ldap.LDAPConnection#setCache(netscape.ldap.LDAPCache)
* @see netscape.ldap.LDAPConnection#getCache
*/
public class LDAPCache implements Serializable {
static final long serialVersionUID = 6275167993337814294L;
/**
* A hashtable of search results. The key is created from the search
* request parameters (see createKey() method). The value is a Vector
* where the first element is a Long integer representing the size
* of all entries, followed by the actual search result entries (of type
* LDAPEntry).
*/
private Hashtable m_cache;
/**
* A list of cached entries ordered by time (augments m_cache). Each
* element in the list is a 2 element Vector where the element at index
* 0 is the key in the m_cache table, and the element at index 1 is the
* time when the entry was created.
* The list is used to track the time-to-live limit and to implement the
* FIFO algorithm when adding new entries; if the size of the new entry
* exceeds the cache available space, the extra space is made by removing
* existing cached results in the order of their entry in the cache.
*/
private Vector m_orderedStruct;
private long m_timeToLive;
private long m_maxSize;
private String[] m_dns;
private long m_remainingSize = 0;
// Count of LDAPConnections that share this cache
private int m_refCnt = 0;
/**
* Delimiter used internally when creating keys
* for the cache.
*/
public static final String DELIM = "#";
private TTLTimer m_timer = null;
private long m_totalOpers = 0;
private long m_hits = 0;
private long m_flushes = 0;
// Debug can be activated by defining debug.cache property
private static boolean m_debug = false;
static {
try {
String traceProp = System.getProperty("debug.cache");
m_debug = (traceProp != null);
}
catch (Exception e) {
;// In browser access to property might not be allowed
}
}
/**
* Constructs a new LDAPCache object, using the
* specified maximum size of the cache (in bytes) and the maximum
* age of cached items (in seconds). When items in the cache
* exceed this age, they are removed from the cache.
*
*
* @param ttl the maximum amount of time that an item can be cached
* (in seconds)
* @param size the maximum size of the cache (in bytes)
*/
public LDAPCache(long ttl, long size)
{
init(ttl, size);
}
/**
* Constructs a new LDAPCache object, using the
* specified maximum size of the cache (in bytes), and the maximum
* age of cached items (in seconds), and an array of the base DNs
* of searches that you want to cache. (For example,
* if the array of base DNs includes o=Airius.com,
* the cache stores search results if the base DN in the search
* request is o=Airius.com.)
*
*
* @param ttl the maximum amount of time that an item can be cached
* (in seconds)
* @param size the maximum size of the cache (in bytes)
* @param dns the list of base DNs of searches that you want to cache.
*/
public LDAPCache(long ttl, long size, String[] dns)
{
init(ttl, size);
m_dns = new String[dns.length];
if ((dns != null) && (dns.length > 0))
for (int i=0; i
*
* @return the maximum age of items in the cache (in
* seconds).
*/
public long getTimeToLive()
{
return m_timeToLive/1000;
}
/**
* Gets the array of base DNs of searches to be cached.
* (Search requests with these base DNs are cached.)
*
*
* @return the array of base DNs.
*/
public String[] getBaseDNs()
{
return m_dns;
}
/**
* Flush the entries identified by DN and scope from the cache.
*
*
* @param dn the distinguished name (or base DN) of the entries
* to be removed from the cache. Use this parameter in conjunction
* with
* @return
*
* @return the available space (in bytes) in the cache.
*/
public long getAvailableSize() {
return m_remainingSize;
}
/**
* Gets the total number of requests for retrieving items from
* the cache. This includes both items successfully found in
* the cache and items not found in the cache.
*
*
* @return the total number of requests for retrieving items from
* the cache.
*/
public long getTotalOperations() {
return m_totalOpers;
}
/**
* Gets the total number of requests which failed to find and
* retrieve an item from the cache.
*
*
* @return the number of requests that did not find and retrieve
* an item in the cache.
*/
public long getNumMisses() {
return (m_totalOpers - m_hits);
}
/**
* Gets the total number of requests which successfully found and
* retrieved an item from the cache.
* @return the number of requests that successfully found and
* retrieved an item from the cache.
*/
public long getNumHits() {
return m_hits;
}
/**
* Gets the total number of entries that are flushed when timer expires
* and
*
* @return the total number of entries that are flushed when timer
* expires.
*/
public long getNumFlushes() {
return m_flushes;
}
/**
* Create a key for a cache entry by concatenating all input parameters
* @return the key for a cache entry
* @exception LDAPException Thrown when failed to create key.
*/
Long createKey(String host, int port, String baseDN, String filter,
int scope, String[] attrs, String bindDN, LDAPConstraints cons)
throws LDAPException {
DN dn = new DN(baseDN);
baseDN = dn.toString();
if (m_dns != null) {
int i=0;
for (; iscope to identify the entries that you want
* removed from the cache. If this parameter is null,
* the entire cache is flushed.
* @param scope the scope identifying the entries that you want
* removed from the cache. The value of this parameter can be
* one of the following:
*
*
* LDAPv2.SCOPE_BASE (to remove the entry identified
* by dn)
* LDAPv2.SCOPE_ONE (to remove the entries that
* have dn as their parent entry)
* LDAPv2.SCOPE_SUB (to remove the entries in the
* subtree under dn in the directory)
* true if the entry is removed from the cache;
* false if the entry is not removed.
*/
public synchronized boolean flushEntries(String dn, int scope) {
if (m_debug)
System.out.println("DEBUG: User request for flushing entry: dn "+
dn+" and scope "+scope);
// if the dn is null, invalidate the whole cache
if (dn == null)
{
// reclaim all the cache spaces
m_remainingSize = m_maxSize;
m_cache.clear();
m_orderedStruct.removeAllElements();
// reset stats
m_totalOpers = m_hits = m_flushes = 0;
return true;
}
DN dn2 = new DN(dn);
Enumeration e = m_cache.keys();
while(e.hasMoreElements()) {
Long key = (Long)e.nextElement();
Vector val = (Vector)m_cache.get(key);
// LDAPEntries start at idx 1, at idx 0 is a Long
// (size of all LDAPEntries returned by search())
int j=1;
int size2=val.size();
for (; jflushEntries is called.
*