/**
* 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.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
/**
* Store for data. Uses the UniqueIdentifier to keep
* data together.
*
* note: this implementation is not synchronized since it makes
* use of a HashMap, which isn't
*
* @author Marc van der Wurff
*
*/
public class DataStore {
public final static Logger logger = Logger.getLogger(DataStore.class.getName());
/**
*
*/
public final static String KEY_PARAMETERS ="$PARAMETER";
/**
* keyword reserverd for passing a pagesize
*/
public final static String KEY_LOCALE = "$LOCALE";
/**
* keyword reserved for passing a pagesize
*/
public final static String KEY_WORD_PAGESIZE = "$PAGESIZE";
/**
* keyword reserved for passing the total amount of pages avialable
*/
public final static String KEY_WORD_PAGESAVAILABLE = "$AMOUNT_PAGESAVAILABLE";
/**
* key to store the error message
*/
public final static String KEY_ERROR_MESSAGE = "$ERROR_MESSAGE";
/**
* keyword reserved for passing the total amount of results avialable
*/
public final static String KEY_WORD_AMNT_RESULTS = "$AMNT_RESULTS";
/**
* keyword reserved for passing a boolean string [true/false] telling to calculate the ttl
* amount of pages that will be available based on the result
*/
public final static String KEY_WORD_CALCULATEPAGESAVAILABLE = "$COUNTPAGESAVAILABLE";
/**
* keyword reserved for passing a pagenumber
*/
public final static String KEY_LOOKUP_DATA = "__$$DATA$$__";
/**
* keyword reserved for passing a pagenumber
*/
public final static String KEY_WORD_PAGE_NUMBER = "$OFFSET";
/**
* keyword reserved for passing the last pagenumber
*/
public final static String KEY_WORD_PAGE_NUMBER_LAST = "MAX";
/**
* keyword reserved for passing a column to sort on
*/
public static final String KEY_WORD_SORT_ON_COLUMN = "$SORT_COLUMN";
/**
* keyword reserved for passing sort order
*/
public static final String KEY_WORD_SORT_ORDER = "$SORT_ORDER";
/**
* keyword reserved for indicating that count is expected as result
*/
public static final String KEY_WORD_COUNT = "$COUNT";
public static final String KEY_WORD_QAFE_BUILT_IN_LIST = "QAFE_BUILT_IN_LIST";
/**
* keys reserved for identifying the models being updated
*/
public static final String KEY_SERVICE_MODIFY = "$SERVICE_MODIFY";
public static final String KEY_SERVICE_MODIFIED_MODELS = "$SERVICE_MODIFIED_MODELS";
public final static String[] KEY_WORDS = {
KEY_WORD_PAGE_NUMBER,
KEY_WORD_PAGESIZE,
KEY_WORD_PAGESAVAILABLE,
KEY_WORD_CALCULATEPAGESAVAILABLE,
KEY_WORD_SORT_ON_COLUMN,
KEY_WORD_SORT_ORDER,
KEY_WORD_COUNT
};
private static Map store = new HashMap();
/**
* Method to check if an entry already exists for given id.
* @param id
* @return - true if given id is contained whitin the store
*/
public static boolean isRegistered(DataIdentifier id){
return DataStore.store.containsKey(id);
}
/**
* method to check if a certain key for a given id exists whitin the datastore
* @param id
* @param key
* @return - true when data exists for id and given key
*/
public static boolean contains(DataIdentifier id, String key){
return DataStore.store.get(id)!=null && ((Data)DataStore.store.get(id)).contains(key);
}
/**
* Method to register with the DataStore so data can be added
* whitin a sequence. This method has a uniqueness check,
* to make sure the key isn't already used whitin the datastore at
* the moment of registration.
* @return uniqueIdentifier - a registration ticket
*/
public static synchronized DataIdentifier register(){
DataIdentifier id = DataIdentifier.create();
/* //since unique is not guaranteed
int tryoutCounter = 5;
while(isRegistered(id) && tryoutCounter-->0){
id = DataIdentifier.create();
}
if(tryoutCounter<0)
throw new UnknownError("random came back 5 times with a used identifier");
*/
DataStore.store.put(id, Data.create());
return id;
}
/**
* Method to store data (value param) for a UniqueId, under the given key.
* If an entry already exists for the given key the data will be overridden
* (like a HashMap.put())
* @param id - uniqueid
* @param key - the key the data will be stored under
* @param value - the value for this entry
* @throws IllegalArgumentException - when id is null or not contained whitin the datastore
*/
public static void store(DataIdentifier id, String key, Object value){
if(id==null)
throw new IllegalArgumentException("Identifier cannot be null, element cannot be stored on null id");
if(!DataStore.isRegistered(id))
throw new IllegalArgumentException("Identifier ["+id+"] hasn't been registered with the datastore or has expired");
if(key==null)
throw new IllegalArgumentException("Cannot store data for null key.");
((Data)DataStore.store.get(id)).add(key, value);
}
public static void store(DataIdentifier id, String key){
store(id, key, null);
}
/**
* Method that iterate through a given map to store data .
* @param id - uniqueid
* @param data - map containing the key value pair
*/
public static void store(DataIdentifier id, Map<String, Object> data){
for(Entry<String, Object> entry: data.entrySet()){
DataStore.store(id, entry.getKey(), entry.getValue());
}
}
/**
* This method gets the value for given dataidentifier and key. This method can return null
* values when the data for a given key is null. If data cannot be found for specified identifier
* a DataNotFoundException is thrown.
* @param id - uniqueid
* @param key - the key the data will be stored under
* @return Object - data found
* @throws IllegalArgumentException - when id is not registered whith the datastore or when the key passed is null
* @throws DataNotFoundException - when no data exists for given key
*
*/
public static Object getValue(DataIdentifier id, String key){
if(!DataStore.isRegistered(id))
throw new IllegalArgumentException("identifier ["+id+"] isn't registered with the datastore or has expired when searching for key:"+key);
if(key==null)
throw new IllegalArgumentException("Cannot get data for null search key:"+key);
Data data = (Data)DataStore.store.get(id);
if(!data.contains(key))
throw new DataNotFoundException("There is no data stored for Key ["+key+"] and DataIdentifier ["+id+"]");
return data.get(key);
}
/**
* Works like the getValue method with the one exception that when there is no data registered
* for the given key null is returned.
* @param id - uniqueid
* @param key - the key the data will be stored under
* @return Object - data found
* @throws IllegalArgumentException - when id is not registered whith the datastore or when the key passed is null
*/
public static Object findValue(DataIdentifier id, String key){
if(!DataStore.isRegistered(id)) {
logger.info("[thread:"+Thread.currentThread().getId()+"]identifier ["+id+"] isn't registered with the datastore or has expired when searching for key:" + key);
return null;
}
if(key==null) {
logger.info("[thread:"+Thread.currentThread().getId()+"] Cannot get data for null search key:" + key);
return null;
}
Data data = (Data)DataStore.store.get(id);
return data.find(key);
}
/**
* Method to remove entire entry for id, also removes id itself (unregisters).
* @param id
*/
public static void unregister(DataIdentifier id){
DataStore.store.remove(id);
}
/**
* Method to clear entries for an id. This method doesnot remove the id
* from the datastore (use unregister for that feature)
* @param id
*/
public static void clear(DataIdentifier id){
((Data)DataStore.store.get(id)).clear();
}
/**
* Method to do a datstore cleanup for data not touched
* for a period greather than given timeout
* @param timeout
*/
public static void cleanUp(long timeout){
long nowMinusTimeout = Calendar.getInstance().getTime().getTime()-timeout;
Set keys = DataStore.store.keySet();
for (Iterator iter = keys.iterator(); iter.hasNext();) {
DataIdentifier id = (DataIdentifier) iter.next();
if(((Data)DataStore.store.get(id)).isTouchedAfter(nowMinusTimeout));
unregister(id);
}
}
/**
* Method for displaying purposes, f.i. in a logfile
* @param id
* @return
*/
public static String toLogString(DataIdentifier id){
return store.get(id)!=null?"Data for key ["+id+"]:\n" + ((Data)store.get(id)).toLogString():null;
}
/**
* Method to return the store as such
* @parem id
*/
public static Map getDataStore(DataIdentifier id){
Data d = (Data) store.get(id);
if (d!=null){
return d.getElements();
}
else {
return null;
}
}
}