JCS3CacheImpl.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.utils.cache;
- import java.io.ByteArrayOutputStream;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.ObjectOutputStream;
- import java.io.OutputStream;
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Enumeration;
- import java.util.List;
- import java.util.Properties;
- import java.util.Set;
- import org.apache.commons.jcs3.JCS;
- import org.apache.commons.jcs3.access.CacheAccess;
- import org.apache.commons.jcs3.admin.CountingOnlyOutputStream;
- import org.apache.commons.jcs3.admin.JCSAdminBean;
- import org.apache.commons.jcs3.engine.CacheElementSerialized;
- import org.apache.commons.jcs3.engine.behavior.ICacheElement;
- import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
- import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
- import org.apache.commons.jcs3.engine.control.CompositeCache;
- import org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache;
- import org.apache.commons.jcs3.log.LogManager;
- import org.openspcoop2.utils.Utilities;
- import org.openspcoop2.utils.UtilsException;
- import org.openspcoop2.utils.properties.CollectionProperties;
- import org.openspcoop2.utils.properties.PropertiesUtilities;
- import org.slf4j.Logger;
- /**
- * JCS3CacheImpl
- *
- * @author Poli Andrea (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class JCS3CacheImpl extends AbstractCacheImpl {
- public static void setLog4jSystem() {
- System.setProperty("jcs.logSystem", LogManager.LOGSYSTEM_LOG4J2);
- }
- public static boolean initialize(Logger logConsole,Logger logCore,
- String cachePropertiesName,
- String rootDirectory,Properties objectProperties,
- String OPENSPCOOP2_LOCAL_HOME,String OPENSPCOOP2_CACHE_PROPERTIES,String OPENSPCOOP2_CACHE_LOCAL_PATH){
- try{
-
- // Originale
- java.util.Properties cacheProperties = new java.util.Properties();
- java.io.File loggerFile = new java.io.File(rootDirectory+cachePropertiesName);
- if(loggerFile .exists() == false ){
- cacheProperties.load(Cache.class.getResourceAsStream("/"+cachePropertiesName));
- }else{
- FileInputStream fin = null;
- try{
- fin = new java.io.FileInputStream(loggerFile);
- cacheProperties.load(fin);
- }finally{
- try{
- if(fin!=null){
- fin.close();
- }
- }catch(Exception eClose){
- // close
- }
- }
- }
-
- // File Local Implementation
- CollectionProperties cachePropertiesRidefinito =
- PropertiesUtilities.searchLocalImplementation(OPENSPCOOP2_LOCAL_HOME,logConsole, OPENSPCOOP2_CACHE_PROPERTIES ,OPENSPCOOP2_CACHE_LOCAL_PATH, rootDirectory);
- if(cachePropertiesRidefinito!=null && cachePropertiesRidefinito.size()>0){
- Enumeration<?> ridefinito = cachePropertiesRidefinito.keys();
- while (ridefinito.hasMoreElements()) {
- String key = (String) ridefinito.nextElement();
- String value = (String) cachePropertiesRidefinito.get(key);
- if(cacheProperties.containsKey(key)){
- //Object o =
- cacheProperties.remove(key);
- }
- cacheProperties.put(key, value);
- //System.out.println("CHECK NUOVO VALORE: "+loggerProperties.get(key));
- }
- }
-
- // File Object Implementation
- if(objectProperties!=null && objectProperties.size()>0){
- Enumeration<?> ridefinito = objectProperties.keys();
- while (ridefinito.hasMoreElements()) {
- String key = (String) ridefinito.nextElement();
- String value = (String) objectProperties.get(key);
- if(cacheProperties.containsKey(key)){
- //Object o =
- cacheProperties.remove(key);
- }
- cacheProperties.put(key, value);
- //System.out.println("CHECK NUOVO VALORE: "+loggerProperties.get(key));
- }
- }
-
- JCS.setConfigProperties(cacheProperties);
-
- return true;
-
- }catch(Exception e){
- logCore.error("Riscontrato errore durante l'inizializzazione del sistema di cache: "
- +e.getMessage(),e);
- return false;
- }
- }
-
-
- private CacheAccess<Object, Serializable> cache = null;
- @SuppressWarnings("unused")
- private JCSAdminBean cacheAdmin = null;
-
- private JCS3CacheImpl() {
- // Metodo usato per le utilities
- setLog4jSystem();
- this.cacheAdmin = new JCSAdminBean();
- }
- public JCS3CacheImpl(String name) throws UtilsException{
- this(name, org.openspcoop2.utils.cache.Cache.DEFAULT_DISABLE_SYNCRONIZED_GET);
- }
- @Deprecated
- private JCS3CacheImpl(String name, boolean disableSyncronizedGet) throws UtilsException{
- super(CacheType.JCS, name);
- setLog4jSystem();
- try{
- this.cacheAdmin = new JCSAdminBean();
- this.cache = JCS.getInstance(this.cacheName);
- if(disableSyncronizedGet) {
- // Dalla versione 3.0 non è più presente la gestione del synchronized
- //this.cache.getCacheControl().setSyncDisabled(disableSyncronizedGet);
- }
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
-
- // *** Inizializzazione ***
-
- @Override
- public int getCacheSize() {
- return this.cache.getCacheAttributes().getMaxObjects();
- }
- @Override
- public void setCacheSize(int cacheSize) {
- // E' necessario prendere l'oggetto e poi risettarlo a causa di un bug.
- ICompositeCacheAttributes attr = this.cache.getCacheAttributes();
- attr.setMaxObjects(cacheSize);
- this.cache.setCacheAttributes(attr);
- }
- @Override
- public CacheAlgorithm getCacheAlgoritm() {
- return CacheAlgorithm.toEnum(this.cache.getCacheAttributes().getCacheName());
- }
- @Override
- public void setCacheAlgoritm(CacheAlgorithm cacheAlgoritm) {
- // E' necessario prendere l'oggetto e poi risettarlo a causa di un bug.
- ICompositeCacheAttributes attr = this.cache.getCacheAttributes();
- attr.setCacheName(cacheAlgoritm.getAlgorithm());
- this.cache.setCacheAttributes(attr);
- }
- @Override
- public long getItemIdleTime() throws UtilsException {
- try{
- return this.cache.getDefaultElementAttributes().getIdleTime();
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @Override
- public void setItemIdleTime(long itemIdleTimeCache) throws UtilsException {
- try{
- // E' necessario prendere l'oggetto e poi risettarlo a causa di un bug.
- IElementAttributes el = this.cache.getDefaultElementAttributes();
- el.setIdleTime(itemIdleTimeCache);
- this.cache.setDefaultElementAttributes(el);
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @Override
- public long getItemLifeTime() throws UtilsException {
- try{
- return this.cache.getDefaultElementAttributes().getMaxLife();
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @Override
- public boolean isEternal() throws UtilsException {
- try{
- return this.cache.getDefaultElementAttributes().getIsEternal();
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @Override
- public void setItemLifeTime(long itemLifeTimeCache) throws UtilsException {
- try{
- // E' necessario prendere l'oggetto e poi risettarlo a causa di un bug.
- IElementAttributes el = this.cache.getDefaultElementAttributes();
- if(itemLifeTimeCache>0) {
- el.setIsEternal(false);
- el.setMaxLife(itemLifeTimeCache);
- }
- else {
- el.setIsEternal(true);
- el.setMaxLife(-1);
- }
- this.cache.setDefaultElementAttributes(el);
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- @Override
- public void build() throws UtilsException{
- // nop; le operazioni di aggiustamento delle dimensioni, si fanno direttamente sugli oggetti
- }
-
-
- // *** Gestione ***
-
- @Override
- public void clear() throws UtilsException{
- if(this.cache!=null){
- try{
- this.cache.clear();
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- }
-
- @Override
- public Object get(String key){
- return this.cache.get(this.formatKeyCache(key));
- }
-
- @Override
- public void remove(String key) throws UtilsException{
- try{
- this.cache.remove(this.formatKeyCache(key));
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- @Override
- public void put(String key,org.openspcoop2.utils.cache.CacheResponse value) throws UtilsException{
- try{
- this.cache.put(this.formatKeyCache(key), value);
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @Override
- public void put(String key,Serializable value) throws UtilsException{
- try{
- this.cache.put(this.formatKeyCache(key), value);
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- private String formatKeyCache(String key) {
- // org/apache/commons/jcs/engine/control/CompositeCache.java
- // if ( cacheElement.getKey() instanceof String
- // && cacheElement.getKey().toString().endsWith( NAME_COMPONENT_DELIMITER ) )
- // {
- // throw new IllegalArgumentException( "key must not end with " + NAME_COMPONENT_DELIMITER
- // + " for a put operation" );
- // }
- //
- // Dove in org.apache.commons.jcs3.engine.behavior.ICache
- // public static final String NAME_COMPONENT_DELIMITER = ":";
- /*StringBuilder bf = new StringBuilder(key);
- if(bf.toString().endsWith(org.apache.commons.jcs3.engine.behavior.ICache.NAME_COMPONENT_DELIMITER)){
- bf.append("_");
- }
- return bf.toString();*/
- if(key.endsWith(org.apache.commons.jcs3.engine.behavior.ICache.NAME_COMPONENT_DELIMITER)) {
- return key+"_";
- }
- else {
- return key;
- }
- }
-
- @Override
- public int getItemCount() throws UtilsException {
- CompositeCache<Object, Serializable> cache = JCSAdminBean.getCompositeCacheManager().getCache(this.cacheName);
- return cache.getSize();
- }
-
- @Override
- public List<String> keys() throws UtilsException {
- try{
-
- List<String> keys = new ArrayList<>();
- Serializable[] keysObject = this.cache.getCacheControl().getKeySet().toArray(new Serializable[0]);
- if(keysObject!=null){
- for (int i = 0; i < keysObject.length; i++) {
- keys.add((String)keysObject[i]);
- }
- }
- return keys;
-
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
-
-
- // *** Info ***
-
- @Override
- public void printStats(OutputStream out, String separator) throws UtilsException{
- this.printStats(this.cacheName,out,separator,true);
- }
-
- private void printStats(String cacheName, OutputStream out, String separator, boolean thisCache) throws UtilsException {
-
- try{
-
- StringBuilder bf = new StringBuilder();
-
- CompositeCache<Object, Serializable> cache = JCSAdminBean.getCompositeCacheManager().getCache(cacheName);
-
- //bf.append(Utilities.convertBytesToFormatString(region.getByteCount()));
- // NOTA: e' stato re-implementato il metodo poiche' casualmente avveniva un errore del tipo:
- // Problem getting byte count. Likley cause is a non serilizable object.null
- // Il problema derivava dall'implementazione del metodo all'interno della classe org/apache/commons/jcs/admin/JCSAdminBean
- // Viene utilizzato l'iterator dentro una struttura dinamica che cambia.
- // A volte, quando poi veniva registrato l'errore soprastante, avveniva questo errore (scoperto aggiungendo stampe nelle classi di JCS)
- // java.util.ConcurrentModificationException
- // at java.util.Hash table$Enumerator.next(Hash table.java:1031)
- // at org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache$IteratorWrapper.next(LRUMemoryCache.java:428)
- // at org.apache.commons.jcs3.admin.JCSAdminBean.getByteCount(JCSAdminBean.java:95)
- int tentativi = 0;
- long sizeAttuale = -1;
- while (tentativi<10) {
- sizeAttuale = this.getByteCount(cache);
- if(this.errorOccursCountingBytes==false){
- break;
- }
- if(thisCache){
- //System.err.println("PROVO ALTRO TENTATIVO");
- tentativi++;
- cache = JCSAdminBean.getCompositeCacheManager().getCache(cacheName);
- }
- else{
- break;
- }
- }
-
-
- bf.append("Nome:");
- bf.append(cacheName);
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("Tipo:");
- bf.append(CacheType.JCS);
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("Stato:");
- bf.append(cache.getStatus());
- bf.append(" ");
-
- bf.append(separator);
-
- // Dalla versione 3.0 non è più presente la gestione del synchronized
- // bf.append("GetSyncDisabled:");
- // bf.append(cache.isSyncDisabled());
- // bf.append(" ");
- //
- // bf.append(separator);
-
- if(cache.getCacheAttributes()!=null){
-
- bf.append("Algoritmo:");
- String cacheAlgoName = cache.getCacheAttributes().getCacheName();
- CacheAlgorithm cacheEnum = CacheAlgorithm.toEnum(cacheAlgoName);
- if(cacheEnum!=null){
- bf.append(cacheEnum.name());
- }else{
- bf.append(cacheAlgoName);
- }
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("Dimensione:");
- bf.append(cache.getCacheAttributes().getMaxObjects());
- bf.append(" ");
-
- bf.append(separator);
-
- }
-
- bf.append("ElementiInCache:");
- bf.append(cache.getSize());
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("MemoriaOccupata:");
- if(this.errorOccursCountingBytes){
- bf.append("[WARN !Error occurs counting bytes, re-try!]");
- }
- bf.append(Utilities.convertBytesToFormatString(sizeAttuale));
- bf.append(" ");
-
- bf.append(separator);
-
- if(cache.getElementAttributes()!=null){
-
- bf.append("IdleTime:");
- long idleTime = cache.getElementAttributes().getIdleTime();
- if(idleTime>0){
- bf.append(Utilities.convertSystemTimeIntoStringMillisecondi(idleTime*1000,false));
- }
- else if(idleTime==0){
- bf.append("0");
- }
- else if(idleTime<0){
- bf.append("Infinito");
- }
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("LifeTime:");
- long lifeTime = cache.getElementAttributes().getMaxLife();
- if(lifeTime>0){
- bf.append(Utilities.convertSystemTimeIntoStringMillisecondi(lifeTime*1000,false));
- }
- else if(lifeTime==0){
- bf.append("0");
- }
- else if(lifeTime<0){
- if(cache.getElementAttributes().getIsEternal()) {
- bf.append("Infinito");
- }
- else {
- bf.append("Infinito (NoEternal?)");
- }
- }
- bf.append(" ");
-
- bf.append(separator);
-
- }
-
- bf.append("PutCount:");
- bf.append(cache.getUpdateCount());
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("HitCount(Aux):");
- bf.append(cache.getHitCountAux());
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("HitCount(Ram):");
- bf.append(cache.getHitCountRam());
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("MissCount(Expired):");
- bf.append(cache.getMissCountExpired());
- bf.append(" ");
-
- bf.append(separator);
-
- bf.append("MissCount(NotFound):");
- bf.append(cache.getMissCountNotFound());
- bf.append(" ");
-
- out.write(bf.toString().getBytes());
-
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- private boolean errorOccursCountingBytes_debug = false;
- private boolean errorOccursCountingBytes = false;
- public <K, V> long getByteCount(CompositeCache<K, V> cache)
- {
- this.errorOccursCountingBytes = false;
-
- if (cache == null)
- {
- throw new IllegalArgumentException("The cache object specified was null.");
- }
- long size = 0;
- IMemoryCache<K, V> memCache = cache.getMemoryCache();
- try {
- for (K key : memCache.getKeySet())
- {
- ICacheElement<K, V> ice = null;
- try
- {
- ice = memCache.get(key);
- }
- catch (IOException e)
- {
- //Modificato per openspcoop
- if(this.errorOccursCountingBytes_debug) {
- System.err.println("["+this.cacheName+"] Element cache get");
- e.printStackTrace(System.err);
- }
- this.errorOccursCountingBytes = true;
- continue;
- //throw new RuntimeException("IOException while trying to get a cached element", e);
- }
- if (ice == null)
- {
- continue;
- }
- if (ice instanceof CacheElementSerialized)
- {
- size += ((CacheElementSerialized<K, V>) ice).getSerializedValue().length;
- }
- else
- {
- Object element = ice.getVal();
- if(element == null) {
- //Modificato per openspcoop
- if(this.errorOccursCountingBytes_debug) {
- System.err.println("["+this.cacheName+"] Element cache is null");
- }
- this.errorOccursCountingBytes = true;
- continue;
- }
- //CountingOnlyOutputStream: Keeps track of the number of bytes written to it, but doesn't write them anywhere.
- CountingOnlyOutputStream counter = new CountingOnlyOutputStream();
- try (ObjectOutputStream out = new ObjectOutputStream(counter);)
- {
- out.writeObject(element);
- }
- catch (IOException e)
- {
- // Modificato per openspcoop
- if(this.errorOccursCountingBytes_debug) {
- System.err.println("["+this.cacheName+"] Element cache writeObject ("+element.getClass().getName()+")");
- e.printStackTrace(System.err);
- }
- this.errorOccursCountingBytes = true;
- continue;
- //throw new RuntimeException("IOException while trying to measure the size of the cached element", e);
- }
- finally
- {
- try
- {
- counter.close();
- }
- catch (IOException e)
- {
- // ignore
- }
- }
- // 4 bytes lost for the serialization header
- size += counter.getCount() - 4;
- }
- }
- }
- catch ( Exception e )
- {
- System.err.println( "Problem getting byte count (Modified by GovWay). Likley cause is a non serilizable object." + e.getMessage() );
- e.printStackTrace(System.err);
- }
- return size;
- }
-
- public static String printAllStats(String separatorStat, String separatorCache) throws UtilsException {
- try{
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- printAllStats(bout,separatorStat,separatorCache);
- bout.flush();
- bout.close();
- return bout.toString();
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- public static void printAllStats(OutputStream out, String separatorStat, String separatorCache) throws UtilsException {
- try{
- JCS3CacheImpl cacheUtility = new JCS3CacheImpl();
-
- Set<String> cacheNames_tmp = JCSAdminBean.getCompositeCacheManager().getCacheNames();
- if(cacheNames_tmp.size()>0) {
- String[] cacheNames = new String[cacheNames_tmp.size()];
- int index = 0;
- for (String name : cacheNames_tmp) {
- cacheNames[index] = name;
- index++;
- }
- Arrays.sort( cacheNames );
- for ( int i = 0; i < cacheNames.length; i++ ) {
- cacheUtility.printStats(cacheNames[i],out,separatorStat,false);
- out.write(separatorCache.getBytes());
- }
- }
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
-
-
-
- // *** Sincronizzazione ***
-
- @SuppressWarnings("deprecation")
- @Override
- @Deprecated
- public void disableSyncronizedGet() throws UtilsException {
- if(this.cache==null) {
- throw new UtilsException("Cache disabled");
- }
- try{
- // Dalla versione 3.0 non è più presente la gestione del synchronized
- //this.cache.getCacheControl().setSyncDisabled(true);
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @SuppressWarnings("deprecation")
- @Override
- @Deprecated
- public boolean isDisableSyncronizedGet() throws UtilsException {
- if(this.cache==null) {
- throw new UtilsException("Cache disabled");
- }
- try{
- // Dalla versione 3.0 non è più presente la gestione del synchronized
- //return this.cache.getCacheControl().isSyncDisabled();
- return true;
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- @SuppressWarnings("deprecation")
- @Override
- @Deprecated
- public void enableDebugSystemOut() throws UtilsException {
- if(this.cache==null) {
- throw new UtilsException("Cache disabled");
- }
- try{
- // Dalla versione 3.0 non è più presente la gestione del synchronized
- //this.cache.getCacheControl().setDebugSystemOut(true);
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- @SuppressWarnings("deprecation")
- @Override
- @Deprecated
- public boolean isEnableDebugSystemOut() throws UtilsException {
- if(this.cache==null) {
- throw new UtilsException("Cache disabled");
- }
- try{
- // Dalla versione 3.0 non è più presente la gestione del synchronized
- //return this.cache.getCacheControl().isDebugSystemOut();
- return false;
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- }