All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.net.sf.ehcache.distribution.JNDIManualRMICacheManagerPeerProvider Maven / Gradle / Ivy

There is a newer version: 4.2.4
Show newest version
/**
 *  Copyright 2003-2006 Greg Luck
 *
 *  Licensed 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 net.sf.ehcache.distribution;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * A provider of RMI CachePeers through JNDI lookup.
 * 

* The design allows for a peer server to go down. When it is up again * the peer will be provided again. *

* The JNDI Context and the CachePeers are cached locally. * When listRemoteCachePeers is called each CachePeer is tested for * staleness. If it is stale, the peer is looked up again in JNDI. * * @author Andy McNutt * @author Greg Luck * @version $Id: JNDIManualRMICacheManagerPeerProvider.java 100 2006-05-30 08:19:29Z gregluck $ */ public class JNDIManualRMICacheManagerPeerProvider implements CacheManagerPeerProvider { private static final Log LOG = LogFactory.getLog(JNDIRMICacheManagerPeerListener.class.getName()); /** * Contains registered JNDI URLs as keys to their Context */ protected Map peerUrls = new HashMap(); /** * CachePeers keyed by jndiProviderUrl */ protected Map cachePeers = new HashMap(); /** * Prevent deadlock accessing peerUrls and cachePeers * with this lock object. */ private final Object lock = new Object(); private CacheManager cacheManager; private boolean isStashContexts = true; private boolean isStashRemoteCachePeers = true; /** * Constructor * * @param isStashRemoteCachePeers * @param isStashContexts */ public JNDIManualRMICacheManagerPeerProvider(boolean isStashContexts, boolean isStashRemoteCachePeers) { this.isStashContexts = isStashContexts; this.isStashRemoteCachePeers = isStashRemoteCachePeers; } /** * Constructor * * @param cacheManager */ public JNDIManualRMICacheManagerPeerProvider(CacheManager cacheManager) { this.cacheManager = cacheManager; } /** * Notifies providers to initialise themselves. * * @throws CacheException */ public void init() { //noop } /** * Register a new peer * * @param jndiProviderUrl */ public void registerPeer(String jndiProviderUrl) { registerPeerToContext(jndiProviderUrl); } /** * Unregisters a peer * * @param jndiProviderUrl */ public void unregisterPeer(String jndiProviderUrl) { synchronized (lock) { peerUrls.remove(jndiProviderUrl); } } /** * @return a list of {@link CachePeer} peers, excluding the local peer. */ public List listRemoteCachePeers(Ehcache cache) throws CacheException { List remoteCachePeers = new ArrayList(); List staleCachePeers = new ArrayList(); String jndiProviderUrl = null; synchronized (lock) { for (Iterator iterator = peerUrls.keySet().iterator(); iterator.hasNext();) { jndiProviderUrl = (String) iterator.next(); String providerUrlCacheName = extractCacheName(jndiProviderUrl); try { if (!providerUrlCacheName.equals(cache.getName())) { continue; } CachePeer cachePeer = lookupCachePeer(jndiProviderUrl); remoteCachePeers.add(cachePeer); } catch (NamingException ne) { LOG.debug(jndiProviderUrl + " " + ne.getMessage()); staleCachePeers.add(jndiProviderUrl); } catch (Exception ex) { LOG.error(ex.getMessage(), ex); throw new CacheException(jndiProviderUrl + " Unable to list remote cache peers. Error was " + ex.getMessage(), ex); } } } if (!staleCachePeers.isEmpty()) { // Do this after loop so don't modify peerUrls in it. unregisterStalePeers(staleCachePeers); } if (LOG.isDebugEnabled()) { try { LOG.debug("listRemoteCachePeers " + cache.getName() + " returning " + remoteCachePeers.size() + " " + printCachePeers(remoteCachePeers)); } catch (RemoteException e) { LOG.warn(e.getMessage(), e); LOG.debug("listRemoteCachePeers " + cache.getName() + " returning " + remoteCachePeers.size()); } } return remoteCachePeers; } /** * Providers may be doing all sorts of exotic things and need to be able to clean up on dispose. * * @throws net.sf.ehcache.CacheException */ public void dispose() throws CacheException { // Remove cached objects synchronized (lock) { peerUrls.clear(); peerUrls = null; cachePeers.clear(); cachePeers = null; } if (LOG.isDebugEnabled()) { LOG.debug("dispose " + toString()); } } /** * Time for a cluster to form. This varies considerably, depending on the implementation. * * @return the time in ms, for a cluster to form */ public long getTimeForClusterToForm() { return 0; } /** * The cacheManager this provider is bound to */ public CacheManager getCacheManager() { return cacheManager; } /** * Register a new peer by looking it up in JNDI and storing * in a local cache the Context. * * @param jndiProviderUrl */ private Context registerPeerToContext(String jndiProviderUrl) { String initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY); if (LOG.isDebugEnabled()) { LOG.debug("registerPeerToContext: " + jndiProviderUrl + " " + extractProviderUrl(jndiProviderUrl) + " with " + initialContextFactory); } Hashtable hashTable = new Hashtable(1); hashTable.put(Context.PROVIDER_URL, extractProviderUrl(jndiProviderUrl)); Context initialContext = null; try { initialContext = new InitialContext(hashTable); registerPeerToContext(jndiProviderUrl, initialContext); } catch (NamingException e) { LOG.warn(jndiProviderUrl + " " + e.getMessage()); registerPeerToContext(jndiProviderUrl, null); } return initialContext; } private void registerPeerToContext(String jndiProviderUrl, Context context) { synchronized (lock) { if (isStashContexts) { peerUrls.put(jndiProviderUrl, context); } else { peerUrls.put(jndiProviderUrl, null); } } } private static String extractCacheName(String jndiProviderUrl) { return jndiProviderUrl.substring(jndiProviderUrl.lastIndexOf('/') + 1); } private static String extractProviderUrl(String jndiProviderUrl) { return jndiProviderUrl.substring(0, jndiProviderUrl.lastIndexOf('/')); } private Context getContext(String jndiProviderUrl) { if (isStashContexts) { synchronized (lock) { return (Context) peerUrls.get(jndiProviderUrl); } } return null; } /** * Call this method after we have checked all the CachePeers for staleness which sets stalePeerUrls. *

* This method sets to null the Context in peerUrls, and * sets to null the CachePeer in cachePeers for each jndiProviderUrl in staleCachePeers. * * @param staleCachePeers - List of stale jndiProviderUrls */ private void unregisterStalePeers(List staleCachePeers) { for (Iterator iterator = staleCachePeers.iterator(); iterator.hasNext();) { String jndiProviderUrl = (String) iterator.next(); registerPeerToContext(jndiProviderUrl, null); registerCachePeer(jndiProviderUrl, null); if (LOG.isDebugEnabled()) { LOG.debug("unregisterStalePeers " + jndiProviderUrl); } } } /** * Get the CachePeer from a local cache. Test isStale. * If it is Stale, look it up in JNDI again and test isStale again. * * @param jndiProviderUrl * @return CachePeer * @throws NamingException when JNDI lookup fails or when the CachePeer is stale and cannot be reestablished. */ private CachePeer lookupCachePeer(String jndiProviderUrl) throws NamingException { CachePeer cachePeer = getCachePeer(jndiProviderUrl); boolean isAlreadyLookedupRemoteCachePeer = false; // The last lookup and test isStale may have caused // cachePeer to be null for jndiProviderUrl. if (cachePeer == null) { cachePeer = lookupRemoteCachePeer(jndiProviderUrl); if (cachePeer == null) { String msg = "cachePeer null after lookup " + jndiProviderUrl; LOG.debug(msg); throw new NamingException(msg); } isAlreadyLookedupRemoteCachePeer = true; } cachePeer = getNonStaleCachePeer(jndiProviderUrl, cachePeer, isAlreadyLookedupRemoteCachePeer); registerCachePeer(jndiProviderUrl, cachePeer); return cachePeer; } /** * @param jndiProviderUrl * @param cachePeer - may not be null * @param isAlreadyLookedupRemoteCachePeer * * @return a CachePeer that is not stale * @throws NamingException */ private CachePeer getNonStaleCachePeer(final String jndiProviderUrl, final CachePeer cachePeer, final boolean isAlreadyLookedupRemoteCachePeer) throws NamingException { boolean isStale = isStale(cachePeer); CachePeer localCachePeer = null; if (isStale) { if (!isAlreadyLookedupRemoteCachePeer) { LOG.debug("CachePeer is stale, looking it up again " + jndiProviderUrl); // The cachePeer is stale. Look it up again. localCachePeer = lookupRemoteCachePeer(jndiProviderUrl); if (!isStale(localCachePeer)) { isStale = false; } } } else { localCachePeer = cachePeer; } if (isStale) { String msg = "After lookup CachePeer is stale " + jndiProviderUrl; LOG.info(msg); throw new NamingException(msg); } return localCachePeer; } private CachePeer getCachePeer(String jndiProviderUrl) { if (isStashRemoteCachePeers) { synchronized (lock) { return (CachePeer) cachePeers.get(jndiProviderUrl); } } return null; } private void registerCachePeer(String jndiProviderUrl, CachePeer cachePeer) { if (isStashRemoteCachePeers) { synchronized (lock) { cachePeers.put(jndiProviderUrl, cachePeer); } } } /** * The last lookup and test isStale may have caused context to be null for jndiProviderUrl. * @param jndiProviderUrl * @return * @throws NamingException */ private CachePeer lookupRemoteCachePeer(String jndiProviderUrl) throws NamingException { Context context = getContext(jndiProviderUrl); if (context == null) { context = registerPeerToContext(jndiProviderUrl); } return (CachePeer) context.lookup(extractCacheName(jndiProviderUrl)); } /** * Any remote method call that doesn't throw RemoteException indicates the cachePeer is not stale * @param cachePeer the peer to check * @return true if the peer is contactable */ private boolean isStale(CachePeer cachePeer) { try { cachePeer.getName(); } catch (RemoteException re) { return true; } return false; } /** * @param cachePeers - List of CachePeers. May not be null. * @return StringBuffer with URL of each CachePeer * @throws RemoteException */ private StringBuffer printCachePeers(List cachePeers) throws RemoteException { Iterator iterator = cachePeers.iterator(); StringBuffer sb = new StringBuffer(); sb.append("CachePeers=["); while (iterator.hasNext()) { CachePeer cachePeer = (CachePeer) iterator.next(); sb.append(" ").append(cachePeer.toString()); } sb.append("]"); return sb; } /** * Returns a string representation of the object. In general, the * toString method returns a string that * "textually represents" this object. The result should * be a concise but informative representation that is easy for a * person to read. * It is recommended that all subclasses override this method. *

* The toString method for class Object * returns a string consisting of the name of the class of which the * object is an instance, the at-sign character `@', and * the unsigned hexadecimal representation of the hash code of the * object. In other words, this method returns a string equal to the * value of: *

*
     * getClass().getName() + '@' + Integer.toHexString(hashCode())
     * 
* * @return a string representation of the object. */ public String toString() { StringBuffer buff = new StringBuffer(); buff.append(super.toString()).append(" cacheManager=") .append(cacheManager).append(" isStashContexts=") .append(isStashContexts).append(" isStashRemoteCachePeers=") .append(isStashRemoteCachePeers); synchronized (lock) { buff.append(" peerUrls=").append(peerUrls).append(" cachePeers=").append(cachePeers); } return buff.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy