/**
* Copyright 2008-2016 Qualogy Solutions B.V.
*
* 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 com.qualogy.qafe.core.datastore;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import com.qualogy.qafe.platform.distribution.DistributionFactory;
//##hkr
public class ApplicationLocalStore {
private final static Logger logger = Logger.getLogger(ApplicationLocalStore.class.getName());
public final static String KEY_USER_ID = "$USER_ID";
public final static String KEY_SHARED_CACHE = "$SHARED_CACHE";
public final static char OBJECT_DELIMITER = '.';
public final static char CONTEXT_DELIMITER = '|';
public final static char ATTRIBUTE_DELIMITER = '@';
public final static String ATTRIBUTE_SIZE = "size";
private static ApplicationLocalStore singleton=null;
private Map<String,Map<String,Object>> store;
private ApplicationLocalStore(){
store = DistributionFactory.getInstance().getDistributionManager().getCacheManager().getDistributedMap(KEY_SHARED_CACHE);
}
public static ApplicationLocalStore getInstance(){
if (singleton==null){
singleton = new ApplicationLocalStore();
}
return singleton;
}
public void storeTemporary(String uuid,String key, Object value){
store(uuid,key,new TemporaryStoreItem(value));
}
public void store(String uuid, String key, Object value){
debug("store: uuid=" + uuid + " - key=" + key + " - value=" + value);
Map<String,Object> localStoreMap = store.get(uuid);
debug("store: uuid=" + uuid + " - localStoreMap=" + localStoreMap);
if (localStoreMap == null){
localStoreMap = new DataMap<String,Object>();
}
localStoreMap.put(key, value);
store(uuid, localStoreMap);
debug("store: uuid=" + uuid + " - localStoreMap=" + localStoreMap);
}
public void deleteAll(String uuid){
Map<String,Object> localStoreMap = store.get(uuid);
debug("delelteAll: uuid=" + uuid + " - localStoreMap=" + localStoreMap);
if (localStoreMap != null){
localStoreMap.clear();
// Make changes affected to the store when using distributed cache in Google AppEngine
store(uuid, localStoreMap);
}
}
public void delete(String uuid, String key){
Map<String,Object> localStoreMap = store.get(uuid);
debug("delete: uuid=" + uuid + " - localStoreMap=" + localStoreMap);
if (localStoreMap != null){
localStoreMap.remove(key);
// Make changes affected to the store when using distributed cache in Google AppEngine
store(uuid, localStoreMap);
}
}
public boolean exists(String uuid){
return (store.get(uuid) != null);
}
public boolean contains(String uuid,String key){
boolean contains=false;
Map<String,Object> localStoreMap = store.get(uuid);
if (localStoreMap!=null){
contains = localStoreMap.containsKey(key);
}
debug("contains: uuid=" + uuid + " - key=" + key + " - contains=" + contains);
return contains;
}
// CHECKSTYLE.OFF: CyclomaticComplexity
public Object retrieve(String uuid, String key){
Object returnValue=null;
Map<String,Object> localStoreMap = store.get(uuid);
debug("retrieve: uuid=" + uuid + " - localStoreMap=" + localStoreMap);
if (localStoreMap!=null){
boolean hasChanges = false;
if (key!=null){
String[] keys = StringUtils.split(key,OBJECT_DELIMITER);
if (keys!=null && keys.length==1 && !key.contains(""+ATTRIBUTE_DELIMITER)){ // simple property
if(key.contains("[")){
returnValue = extractDataMapOfIndexFromList(localStoreMap, key);
} else {
returnValue = localStoreMap.get(key);
}
debug("retrieve: uuid=" + uuid + " - key=" + key + " - returnValue=" + returnValue);
if (returnValue instanceof TemporaryStoreItem){
returnValue = ((TemporaryStoreItem)returnValue).getObject();
localStoreMap.remove(key);
hasChanges = true;
debug("retrieve: uuid=" + uuid + " - returnValue(TemporaryStoreItem)=" + returnValue);
}
} else if (keys.length==2){ // nested object
Object mapObject = null;
if(keys[0].contains("[")){
mapObject = extractDataMapOfIndexFromList(localStoreMap, keys[0]);
} else {
mapObject = localStoreMap.get(keys[0]);
}
debug("retrieve: uuid=" + uuid + " - key=" + key + " - o=" + mapObject);
if (mapObject instanceof Map){
returnValue = ((Map)mapObject).get(keys[1]);
debug("retrieve: uuid=" + uuid + " - returnValue=" + returnValue);
if (returnValue instanceof TemporaryStoreItem){
returnValue = ((TemporaryStoreItem)returnValue).getObject();
localStoreMap.remove(keys[1]);
hasChanges = true;
debug("retrieve: uuid=" + uuid + " - returnValue(TemporaryStoreItem)=" + returnValue);
}
}
} else {
if (key.contains(""+ATTRIBUTE_DELIMITER)){
String attribute = key.substring(key.indexOf(ATTRIBUTE_DELIMITER)+1,key.length());
String elementKey = key.substring(0,key.indexOf(ATTRIBUTE_DELIMITER));
Object object = localStoreMap.get(elementKey);
debug("retrieve: uuid=" + uuid + " - key=" + key + " - object=" + object);
if (object instanceof Collection){
if (ATTRIBUTE_SIZE.equals(attribute)){
returnValue = ((Collection)object).size();
debug("retrieve: uuid=" + uuid + " - size=" + returnValue);
}
}
}
}
}
if (hasChanges) {
// Make changes affected to the store when using distributed cache in Google AppEngine
store(uuid, localStoreMap);
}
}
return returnValue;
}
// CHECKSTYLE.ON: CyclomaticComplexity
/**
* Method to add or update the object in the localstore.
*
* Checks:
* 1. if original is list and toBeAddOrUpdated is list, toBeAddOrUpdated
* will replace old value
* 2. if original is list and toBeAddOrUpdated is not a list, toBeAddOrUpdated
* will be set(if object reference exists) or added to list
* 3. if object in store is null, given object is stored
* @param uuid
* @param key
* @param original
* @return
*/
public void addOrUpdate(String uuid, String key, Object value){
Object updated = update(uuid, key, value);
if (updated == null){
store(uuid, key, value);
}
}
/**
* Method to update the object in the localstore.
*
* Checks:
* 1. if original is list and toBeAddOrUpdated is list, toBeAddOrUpdated
* will replace old value
* 2. if original is list and toBeAddOrUpdated is not a list, toBeAddOrUpdated
* will be set(if object reference exists) or added to list
* @param uuid
* @param key
* @param original
* @return
*/
public Object update(String uuid, String key, Object value){
Object original = retrieve(uuid, key);
if (original instanceof List){
if(value instanceof List){
original = value;
}else{
Iterator itr = ((List)original).iterator();
int index=0;
boolean found=false;
while(itr.hasNext()&& !found){
if (itr.next().equals(value)){
found=true;
} else {
index++;
}
}
if (found){
((List)original).set(index, value);
}else{
((List)original).add(value);
}
}
}else if(original!=null){
original = value;
}
return value;
}
private Object extractDataMapOfIndexFromList(Map<String,Object> localStoreMap, String key) {
String extractedKey = key.substring(0, key.indexOf("["));
int index = Integer.parseInt(key.substring(key.indexOf("[")+1, key.indexOf("]")));
List<DataMap> retrievedList = (List<DataMap>)localStoreMap.get(extractedKey);
return retrievedList.get(index);
}
private void store(String uuid, Map map){
store.put(uuid, map);
}
private void debug(String message) {
logger.fine(message);
}
public String toLogString(String uuid){
return store.get(uuid)!=null?"LocalData for key ["+uuid+"]:\n" + store.get(uuid).toString():null;
}
}