MOB-659 (part 1 of 2) - improve namespace cache reset (should work even with null / cache)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13949 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2009-04-15 09:43:03 +00:00
parent 7c947bb548
commit 37911972ce
8 changed files with 313 additions and 290 deletions

View File

@@ -814,10 +814,7 @@
<property name="tenantService"> <property name="tenantService">
<ref bean="tenantService"/> <ref bean="tenantService"/>
</property> </property>
<property name="urisCache"> <property name="namespaceDataCache">
<ref bean="urisCache"/>
</property>
<property name="prefixesCache">
<ref bean="prefixesCache"/> <ref bean="prefixesCache"/>
</property> </property>
</bean> </bean>

View File

@@ -379,6 +379,7 @@
<!-- Dictionary / Namespace (tenant-based) --> <!-- Dictionary / Namespace (tenant-based) -->
<!-- dictionary models -->
<cache <cache
name="org.alfresco.cache.uriToModelsCache" name="org.alfresco.cache.uriToModelsCache"
maxElementsInMemory="100" maxElementsInMemory="100"
@@ -393,13 +394,7 @@
overflowToDisk="false" overflowToDisk="false"
/> />
<cache <!-- dictionary namespaces -->
name="org.alfresco.cache.urisCache"
maxElementsInMemory="100"
eternal="true"
overflowToDisk="false"
/>
<cache <cache
name="org.alfresco.cache.prefixesCache" name="org.alfresco.cache.prefixesCache"
maxElementsInMemory="100" maxElementsInMemory="100"

View File

@@ -908,22 +908,6 @@
</cache> </cache>
<cache
name="org.alfresco.cache.urisCache"
maxElementsInMemory="100"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache <cache
name="org.alfresco.cache.prefixesCache" name="org.alfresco.cache.prefixesCache"
maxElementsInMemory="100" maxElementsInMemory="100"

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -39,6 +39,7 @@ import net.sf.ehcache.CacheManager;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData;
import org.alfresco.repo.dictionary.constraint.RegexConstraint; import org.alfresco.repo.dictionary.constraint.RegexConstraint;
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint; import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.SingleTServiceImpl;
@@ -125,19 +126,12 @@ public class DictionaryDAOTest extends TestCase
{ {
CacheManager cacheManager = new CacheManager(); CacheManager cacheManager = new CacheManager();
Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L); Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L);
cacheManager.addCache(urisEhCache); cacheManager.addCache(namespaceEhCache);
EhCacheAdapter<String, List<String>> urisCache = new EhCacheAdapter<String, List<String>>(); EhCacheAdapter<String, NamespaceData> namespaceCache = new EhCacheAdapter<String, NamespaceData>();
urisCache.setCache(urisEhCache); namespaceCache.setCache(namespaceEhCache);
namespaceDAO.setUrisCache(urisCache); namespaceDAO.setNamespaceDataCache(namespaceCache);
Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L);
cacheManager.addCache(prefixesEhCache);
EhCacheAdapter<String, Map<String, String>> prefixesCache = new EhCacheAdapter<String, Map<String, String>>();
prefixesCache.setCache(prefixesEhCache);
namespaceDAO.setPrefixesCache(prefixesCache);
} }

View File

@@ -1,3 +1,27 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.dictionary; package org.alfresco.repo.dictionary;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@@ -11,7 +35,7 @@ import net.sf.ehcache.CacheManager;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.dictionary.M2ModelDiff; import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData;
import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.SingleTServiceImpl;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -784,19 +808,12 @@ public class DiffModelTest extends TestCase
{ {
CacheManager cacheManager = new CacheManager(); CacheManager cacheManager = new CacheManager();
Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L); Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L);
cacheManager.addCache(urisEhCache); cacheManager.addCache(namespaceEhCache);
EhCacheAdapter<String, List<String>> urisCache = new EhCacheAdapter<String, List<String>>(); EhCacheAdapter<String, NamespaceData> namespaceCache = new EhCacheAdapter<String, NamespaceData>();
urisCache.setCache(urisEhCache); namespaceCache.setCache(namespaceEhCache);
namespaceDAO.setUrisCache(urisCache); namespaceDAO.setNamespaceDataCache(namespaceCache);
Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L);
cacheManager.addCache(prefixesEhCache);
EhCacheAdapter<String, Map<String, String>> prefixesCache = new EhCacheAdapter<String, Map<String, String>>();
prefixesCache.setCache(prefixesEhCache);
namespaceDAO.setPrefixesCache(prefixesCache);
} }
public void testDeleteModel() public void testDeleteModel()

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -55,9 +55,12 @@ public class NamespaceDAOImpl implements NamespaceDAO
private Lock readLock = lock.readLock(); private Lock readLock = lock.readLock();
private Lock writeLock = lock.writeLock(); private Lock writeLock = lock.writeLock();
// internal caches that are clusterable // Internal cache (clusterable)
private SimpleCache<String, List<String>> urisCache; private SimpleCache<String, NamespaceData> namespaceDataCache;
private SimpleCache<String, Map<String, String>> prefixesCache;
// used to reset the cache
private ThreadLocal<NamespaceData> namespaceDataThreadLocal = new ThreadLocal<NamespaceData>();
private ThreadLocal<NamespaceData> defaultNamespaceDataThreadLocal = new ThreadLocal<NamespaceData>();
// Dependencies // Dependencies
private TenantService tenantService; private TenantService tenantService;
@@ -69,14 +72,9 @@ public class NamespaceDAOImpl implements NamespaceDAO
this.tenantService = tenantService; this.tenantService = tenantService;
} }
public void setUrisCache(SimpleCache<String, List<String>> urisCache) public void setNamespaceDataCache(SimpleCache<String, NamespaceData> namespaceDataCache)
{ {
this.urisCache = urisCache; this.namespaceDataCache = namespaceDataCache;
}
public void setPrefixesCache(SimpleCache<String, Map<String, String>> prefixesCache)
{
this.prefixesCache = prefixesCache;
} }
public void registerDictionary(DictionaryDAO dictionaryDAO) public void registerDictionary(DictionaryDAO dictionaryDAO)
@@ -90,15 +88,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
*/ */
public void init() public void init()
{ {
String tenantDomain = getTenantDomain(); initNamespace(getTenantDomain());
putUrisCtx(tenantDomain, new ArrayList<String>());
putPrefixesCtx(tenantDomain, new HashMap<String, String>());
if (logger.isDebugEnabled())
{
logger.debug("Empty namespaces initialised");
}
} }
/** /**
@@ -108,8 +98,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
{ {
String tenantDomain = getTenantDomain(); String tenantDomain = getTenantDomain();
removeUrisCtx(tenantDomain); removeNamespaceData(tenantDomain);
removePrefixesCtx(tenantDomain);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
@@ -118,31 +107,90 @@ public class NamespaceDAOImpl implements NamespaceDAO
} }
/** /**
* Resets the namespaces (by resetting the dictionary) * Resets the namespaces (by re-initialising the dictionary)
*/ */
private void reset() private NamespaceData reset(String tenantDomain)
{ {
if (logger.isDebugEnabled()) if (dictionaryDAO == null)
{ {
logger.debug("Resetting namespaces ..."); // Unexpected
} throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset");
}
if (dictionaryDAO == null) if (logger.isDebugEnabled())
{ {
// Unexpected logger.debug("Resetting namespaces ...");
throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset"); }
}
else
{
dictionaryDAO.reset();
}
if (logger.isDebugEnabled()) dictionaryDAO.init();
{
logger.debug("... resetting namespaces completed"); NamespaceData namespaceData = getNamespaceData(tenantDomain);
}
if (logger.isDebugEnabled())
{
logger.debug("... resetting namespaces completed");
}
return namespaceData;
} }
private NamespaceData initNamespace(String tenantDomain)
{
try
{
createNamespaceLocal(tenantDomain);
NamespaceData namespaceData = initNamespaceData(tenantDomain);
if (namespaceData == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to init namespaceData " + tenantDomain);
}
try
{
writeLock.lock();
namespaceDataCache.put(tenantDomain, namespaceData);
}
finally
{
writeLock.unlock();
}
return namespaceData;
}
finally
{
try
{
readLock.lock();
if (namespaceDataCache.get(tenantDomain) != null)
{
removeNamespaceLocal(tenantDomain);
}
}
finally
{
readLock.unlock();
}
}
}
private NamespaceData initNamespaceData(String tenantDomain)
{
getNamespaceData(tenantDomain).setUrisCache(new ArrayList<String>());
getNamespaceData(tenantDomain).setPrefixesCache(new HashMap<String, String>());
if (logger.isDebugEnabled())
{
logger.debug("Empty namespaces initialised");
}
return getNamespaceDataLocal(tenantDomain);
}
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.ref.NamespacePrefixResolver#getURIs() * @see org.alfresco.repo.ref.NamespacePrefixResolver#getURIs()
*/ */
@@ -343,6 +391,120 @@ public class NamespaceDAOImpl implements NamespaceDAO
} }
} }
// re-entrant (eg. via reset)
private NamespaceData getNamespaceData(String tenantDomain)
{
NamespaceData namespaceData = null;
try
{
// check cache first - return if set
readLock.lock();
namespaceData = namespaceDataCache.get(tenantDomain);
if (namespaceData != null)
{
return namespaceData; // return cached config
}
}
finally
{
readLock.unlock();
}
// check threadlocal second - return if set
namespaceData = getNamespaceDataLocal(tenantDomain);
if (namespaceData != null)
{
return namespaceData; // return local namespaceData
}
// reset caches - may have been invalidated (e.g. in a cluster)
namespaceData = reset(tenantDomain);
if (namespaceData == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to get namespaceData " + tenantDomain);
}
return namespaceData;
}
// create threadlocal
private void createNamespaceLocal(String tenantDomain)
{
// create threadlocal, if needed
NamespaceData namespaceData = getNamespaceDataLocal(tenantDomain);
if (namespaceData == null)
{
namespaceData = new NamespaceData(tenantDomain);
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{
defaultNamespaceDataThreadLocal.set(namespaceData);
}
else
{
namespaceDataThreadLocal.set(namespaceData);
}
}
}
// get threadlocal
private NamespaceData getNamespaceDataLocal(String tenantDomain)
{
NamespaceData namespaceData = null;
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{
namespaceData = this.defaultNamespaceDataThreadLocal.get();
}
else
{
namespaceData = this.namespaceDataThreadLocal.get();
}
// check to see if domain switched (eg. during login)
if ((namespaceData != null) && (tenantDomain.equals(namespaceData.getTenantDomain())))
{
return namespaceData; // return threadlocal, if set
}
return null;
}
// remove threadlocal
private void removeNamespaceLocal(String tenantDomain)
{
if (tenantDomain.equals(TenantService.DEFAULT_DOMAIN))
{
defaultNamespaceDataThreadLocal.set(null); // it's in the cache, clear the threadlocal
}
else
{
namespaceDataThreadLocal.set(null); // it's in the cache, clear the threadlocal
}
}
private void removeNamespaceData(String tenantDomain)
{
try
{
writeLock.lock();
if (namespaceDataCache.get(tenantDomain) != null)
{
namespaceDataCache.remove(tenantDomain);
}
removeNamespaceLocal(tenantDomain);
}
finally
{
writeLock.unlock();
}
}
/** /**
* Get URIs from the cache (in the context of the current user's tenant domain) * Get URIs from the cache (in the context of the current user's tenant domain)
* *
@@ -361,80 +523,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
*/ */
private List<String> getUrisCtx(String tenantDomain) private List<String> getUrisCtx(String tenantDomain)
{ {
List<String> uris = null; return getNamespaceData(tenantDomain).getUrisCache();
try
{
readLock.lock();
uris = urisCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (uris == null)
{
reset(); // reset caches - may have been invalidated (e.g. in a cluster)
try
{
readLock.lock();
uris = urisCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (uris == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise urisCache " + tenantDomain);
}
}
return uris;
}
/**
* Put URIs into the cache
*
* @param tenantDomain
* @param uris
*/
private void putUrisCtx(String tenantDomain, List<String> uris)
{
try
{
writeLock.lock();
urisCache.put(tenantDomain, uris);
}
finally
{
writeLock.unlock();
}
}
/**
* Remove URIs from the cache
*
* @param tenantDomain
*/
private void removeUrisCtx(String tenantDomain)
{
try
{
writeLock.lock();
if (urisCache.get(tenantDomain) != null)
{
urisCache.get(tenantDomain).clear();
urisCache.remove(tenantDomain);
}
}
finally
{
writeLock.unlock();
}
} }
/** /**
@@ -455,80 +544,7 @@ public class NamespaceDAOImpl implements NamespaceDAO
*/ */
private Map<String, String> getPrefixesCtx(String tenantDomain) private Map<String, String> getPrefixesCtx(String tenantDomain)
{ {
Map<String, String> prefixes = null; return getNamespaceData(tenantDomain).getPrefixesCache();
try
{
readLock.lock();
prefixes = prefixesCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (prefixes == null)
{
reset(); // reset caches - may have been invalidated (e.g. in a cluster)
try
{
readLock.lock();
prefixes = prefixesCache.get(tenantDomain);
}
finally
{
readLock.unlock();
}
if (prefixes == null)
{
// unexpected
throw new AlfrescoRuntimeException("Failed to re-initialise prefixesCache " + tenantDomain);
}
}
return prefixes;
}
/**
* Put prefixes into the cache
*
* @param tenantDomain
* @param prefixes
*/
private void putPrefixesCtx(String tenantDomain, Map<String, String> prefixes)
{
try
{
writeLock.lock();
prefixesCache.put(tenantDomain, prefixes);
}
finally
{
writeLock.unlock();
}
}
/**
* Remove prefixes from the cache
*
* @param tenantDomain
*/
private void removePrefixesCtx(String tenantDomain)
{
try
{
writeLock.lock();
if (prefixesCache.get(tenantDomain) != null)
{
prefixesCache.get(tenantDomain).clear();
prefixesCache.remove(tenantDomain);
}
}
finally
{
writeLock.unlock();
}
} }
/** /**
@@ -538,4 +554,42 @@ public class NamespaceDAOImpl implements NamespaceDAO
{ {
return tenantService.getCurrentUserDomain(); return tenantService.getCurrentUserDomain();
} }
/* package */ class NamespaceData
{
private List<String> urisCache;
private Map<String, String> prefixesCache;
private String tenantDomain;
public NamespaceData(String tenantDomain)
{
this.tenantDomain = tenantDomain;
}
public String getTenantDomain()
{
return tenantDomain;
}
public List<String> getUrisCache()
{
return urisCache;
}
public void setUrisCache(List<String> urisCache)
{
this.urisCache = urisCache;
}
public Map<String, String> getPrefixesCache()
{
return prefixesCache;
}
public void setPrefixesCache(Map<String, String> prefixesCache)
{
this.prefixesCache = prefixesCache;
}
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -32,6 +32,7 @@ import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager; import net.sf.ehcache.CacheManager;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.dictionary.NamespaceDAOImpl.NamespaceData;
import org.alfresco.repo.tenant.SingleTServiceImpl; import org.alfresco.repo.tenant.SingleTServiceImpl;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -132,18 +133,11 @@ public class TestModel
{ {
CacheManager cacheManager = new CacheManager(); CacheManager cacheManager = new CacheManager();
Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L); Cache namespaceEhCache = new Cache("namespaceCache", 50, false, true, 0L, 0L);
cacheManager.addCache(urisEhCache); cacheManager.addCache(namespaceEhCache);
EhCacheAdapter<String, List<String>> urisCache = new EhCacheAdapter<String, List<String>>(); EhCacheAdapter<String, NamespaceData> namespaceCache = new EhCacheAdapter<String, NamespaceData>();
urisCache.setCache(urisEhCache); namespaceCache.setCache(namespaceEhCache);
namespaceDAO.setUrisCache(urisCache); namespaceDAO.setNamespaceDataCache(namespaceCache);
Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L);
cacheManager.addCache(prefixesEhCache);
EhCacheAdapter<String, Map<String, String>> prefixesCache = new EhCacheAdapter<String, Map<String, String>>();
prefixesCache.setCache(prefixesEhCache);
namespaceDAO.setPrefixesCache(prefixesCache);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2007 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -27,13 +27,13 @@ package org.alfresco.repo.policy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.ehcache.Cache; import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager; import net.sf.ehcache.CacheManager;
import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.cache.EhCacheAdapter;
import org.alfresco.repo.cache.NullCache;
import org.alfresco.repo.dictionary.DictionaryBootstrap; import org.alfresco.repo.dictionary.DictionaryBootstrap;
import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.dictionary.DictionaryComponent;
import org.alfresco.repo.dictionary.DictionaryDAOImpl; import org.alfresco.repo.dictionary.DictionaryDAOImpl;
@@ -112,23 +112,11 @@ public class PolicyComponentTest extends TestCase
dictionaryDAO.setCompiledModelsCache(compileModelCache); dictionaryDAO.setCompiledModelsCache(compileModelCache);
} }
@SuppressWarnings("unchecked")
private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO) private void initNamespaceCaches(NamespaceDAOImpl namespaceDAO)
{ {
CacheManager cacheManager = new CacheManager(); // note: unit tested here with null cache
namespaceDAO.setNamespaceDataCache(new NullCache());
Cache urisEhCache = new Cache("urisCache", 50, false, true, 0L, 0L);
cacheManager.addCache(urisEhCache);
EhCacheAdapter<String, List<String>> urisCache = new EhCacheAdapter<String, List<String>>();
urisCache.setCache(urisEhCache);
namespaceDAO.setUrisCache(urisCache);
Cache prefixesEhCache = new Cache("prefixesCache", 50, false, true, 0L, 0L);
cacheManager.addCache(prefixesEhCache);
EhCacheAdapter<String, Map<String, String>> prefixesCache = new EhCacheAdapter<String, Map<String, String>>();
prefixesCache.setCache(prefixesEhCache);
namespaceDAO.setPrefixesCache(prefixesCache);
} }
public void testJavaBehaviour() public void testJavaBehaviour()