AbstractKeystoreCache.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 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.security.keystore.cache;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.codec.digest.DigestUtils;
import org.openspcoop2.security.SecurityException;
import org.openspcoop2.utils.cache.Cache;
import org.openspcoop2.utils.date.DateManager;
import org.openspcoop2.utils.date.DateUtils;
/**
* AbstractKeystoreCache
*
* @author Andrea Poli (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public abstract class AbstractKeystoreCache<T extends Serializable> {
private int cacheLifeSecond = -1;
private int cacheSize = -1;
private Map<String, KeystoreCacheEntry<T>> cacheMap = new ConcurrentHashMap<>();
private Cache cacheJCS = null;
private final org.openspcoop2.utils.Semaphore lockCache = new org.openspcoop2.utils.Semaphore(this.getClass().getSimpleName());
public void setKeystoreCacheParameters(int cacheLifeSecond,int cacheSize){
this.cacheLifeSecond = cacheLifeSecond;
this.cacheSize = cacheSize;
}
public void setCacheJCS(int cacheLifeSecond,Cache cacheJCS) {
this.cacheLifeSecond = cacheLifeSecond;
this.cacheJCS = cacheJCS;
}
public void updateCacheLifeSecond(int cacheLifeSecond) {
this.cacheLifeSecond = cacheLifeSecond;
}
public T getKeystore(String keyParam) throws SecurityException{
KeystoreCacheEntry<T> o = this.getObjectFromCache(keyParam);
if(o==null){
throw new SecurityException("Keystore with key ["+keyParam+"] not found");
}
else {
return estraiKeystore(o);
}
}
public T getKeystoreAndCreateIfNotExists(String keyParam,Object ... params) throws SecurityException{
KeystoreCacheEntry<T> o = this.getObjectFromCache(keyParam);
if(o==null){
/**System.out.println("NON trovato ["+key+"], creo...");*/
return initKeystore(keyParam, params);
}
else {
/**System.out.println("GIA PRESENTE ["+key+"] ESTRAGGO");*/
return estraiKeystore(o);
}
}
public T getKeystore(byte[] keystore) throws SecurityException{
String keyParam = buildKeyCacheFromBytes(keystore);
return getKeystore(keyParam);
}
public T getKeystoreAndCreateIfNotExists(byte[] keystore,Object ... params) throws SecurityException{
String keyParam = buildKeyCacheFromBytes(keystore);
List<Object> lArgs = new ArrayList<>();
lArgs.add(keystore);
if(params!=null && params.length>0) {
lArgs.addAll(Arrays.asList(params));
}
return getKeystoreAndCreateIfNotExists(keyParam, lArgs.toArray());
}
public abstract T createKeystore(String key,Object ... params) throws SecurityException;
public abstract String getPrefixKey();
/* UTILITY */
public static String buildKeyCacheFromBytes(byte[] keystore) throws SecurityException {
if(keystore==null) {
throw new SecurityException("Keystore undefined");
}
return DigestUtils.sha256Hex(keystore);
}
@SuppressWarnings("unchecked")
private KeystoreCacheEntry<T> getObjectFromCache(String keyParam) {
String keyCache = this.getPrefixKey() + keyParam;
KeystoreCacheEntry<T> o = null;
if(this.cacheJCS!=null) {
Object object = this.cacheJCS.get(keyCache);
if(object!=null) {
o = (KeystoreCacheEntry<T>) object;
}
}
else {
o = this.cacheMap.get(keyCache);
}
return o;
}
private T initKeystore(String keyParam,Object ... params) throws SecurityException{
this.lockCache.acquireThrowRuntime("initKeystore");
try {
String keyCache = this.getPrefixKey() + keyParam;
KeystoreCacheEntry<T> o = this.getObjectFromCache(keyCache);
if(o==null) {
T keystore = createKeystore(keyParam, params);
KeystoreCacheEntry<T> cacheEntry = new KeystoreCacheEntry<>();
cacheEntry.setKey(keyCache);
cacheEntry.setKeystore(keystore);
cacheEntry.setDate(DateManager.getDate());
if(this.cacheJCS!=null) {
try {
this.cacheJCS.put(keyCache, cacheEntry);
}catch(Exception e) {
throw new SecurityException(e.getMessage(),e);
}
}
else {
this.cacheMap.put(keyCache, cacheEntry);
}
/**System.out.println("CREATO ["+key+"] !!!! DATA["+cacheEntry.getDate()+"]"); */
return keystore;
}
else {
return estraiKeystore(o);
}
}finally {
this.lockCache.release("initKeystore");
}
}
private void removeKeystore(String key) throws SecurityException{
this.lockCache.acquireThrowRuntime("removeKeystore");
try {
if(this.cacheJCS!=null) {
try {
this.cacheJCS.remove(key);
}catch(Exception e) {
throw new SecurityException(e.getMessage(),e);
}
}
else {
this.cacheMap.remove(key);
}
}finally {
this.lockCache.release("removeKeystore");
}
}
public void removeObjectFromCache(String keyParam) throws SecurityException {
String keyCache = this.getPrefixKey() + keyParam;
removeKeystore(keyCache);
}
public List<String> keys() throws SecurityException{
List<String> keys = new ArrayList<>();
this.lockCache.acquireThrowRuntime("keys");
try {
if(this.cacheJCS!=null) {
try {
List<String> l = this.cacheJCS.keys();
if(l!=null && !l.isEmpty()) {
keys.addAll(l);
}
}catch(Exception e) {
throw new SecurityException(e.getMessage(),e);
}
}
else {
if(!this.cacheMap.isEmpty()) {
keys.addAll(this.cacheMap.keySet());
}
}
}finally {
this.lockCache.release("keys");
}
return keys;
}
private T estraiKeystore(KeystoreCacheEntry<T> entry) throws SecurityException{
T keystore = entry.getKeystore();
if(this.cacheLifeSecond>-1){
long scadenza = entry.getDate().getTime()+this.cacheLifeSecond*1000;
long now = DateManager.getTimeMillis();
if(scadenza<now){
/**System.out.println("SCADUTO PER DATA ["+entry.getKey()+"] ["+scadenza+"] ["+now+"]");*/
removeKeystore(entry.getKey());
}
}
if(this.cacheJCS==null &&
this.cacheSize>-1 &&
this.cacheMap.size()>this.cacheSize){
/**System.out.println("ECCEDUTA DIMENSIONE ["+entry.getKey()+"]");*/
clearCacheMap();
}
return keystore;
}
private void clearCacheMap(){
this.lockCache.acquireThrowRuntime("clearCacheMap");
try {
this.cacheMap.clear();
}finally {
this.lockCache.release("clearCacheMap");
}
}
}
class KeystoreCacheEntry<T extends Serializable> implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public String toString() {
StringBuilder bf = new StringBuilder();
bf.append("Data ").append(DateUtils.getSimpleDateFormatMs().format(this.date)).append("\n");
bf.append(this.keystore.toString());
return bf.toString();
}
private String key;
private T keystore;
private Date date;
public T getKeystore() {
return this.keystore;
}
public void setKeystore(T keystore) {
this.keystore = keystore;
}
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
public String getKey() {
return this.key;
}
public void setKey(String key) {
this.key = key;
}
}