// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.dataquality.indicators.mapdb;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentNavigableMap;
import org.mapdb.BTreeKeySerializer;
import org.mapdb.BTreeKeySerializer.BasicKeySerializer;
import org.mapdb.BTreeMap;
import org.mapdb.DB.BTreeMapMaker;
import org.mapdb.Fun;
import org.mapdb.Pump;
import org.mapdb.Serializer;
import org.talend.cwm.indicator.DataValidation;
/**
* created by talend on Aug 5, 2014 Detailled comment
*
*/
public class DBMap<K, V> extends AbstractDB<K> implements ConcurrentNavigableMap<K, V> {
protected ConcurrentNavigableMap<K, V> dbMap = null;
protected String mapName = "testDBMap" + new Random().nextLong(); //$NON-NLS-1$
protected TalendSerializerBase talendSerializerBase = new TalendSerializerBase();
protected BasicKeySerializer talendBasicKeySerializer = new BTreeKeySerializer.BasicKeySerializer(talendSerializerBase);
public DBMap() {
initDefaultDB();
initMap();
}
public DBMap(String parentFullPathStr, String fileName) {
if (!checkParameter(parentFullPathStr, fileName)) {
return;
}
initDefaultDB(parentFullPathStr, fileName);
initMap();
}
public DBMap(String parentFullPathStr, String fileName, String mapName) {
this(parentFullPathStr, fileName, mapName, 0l);
}
public DBMap(String parentFullPathStr, String fileName, String mapName, Long limSize) {
if (!checkParameter(parentFullPathStr, fileName)) {
return;
}
initDefaultDB(parentFullPathStr, fileName);
this.limitSize = limSize;
initMap(mapName);
}
protected void initMap() {
dbMap = getDB().createTreeMap(mapName).keySerializer(talendBasicKeySerializer).comparator(new DBMapCompartor())
.valueSerializer(talendSerializerBase).make();
}
protected void initMap(String theMapName) {
mapName = theMapName;
if (getDB().exists(mapName)) {
dbMap = getDB().get(mapName);
} else {
BTreeMapMaker treeMapMaker = getDB().createTreeMap(mapName);
if (MapDBContent.isValuesOutsideNodesEnable()) {
treeMapMaker = treeMapMaker.valuesOutsideNodesEnable();
}
dbMap = treeMapMaker.keySerializer(talendBasicKeySerializer).comparator(new DBMapCompartor())
.valueSerializer(talendSerializerBase).make();
}
}
public <VV> BTreeMap<K, VV> pumpSource(Fun.Function1<VV, K> valueExtractor) {
DBMapCompartor dbMapCompartor = new DBMapCompartor();
Iterator<K> sortIterator = Pump.sort(dbMap.keySet().iterator(), false, 100000, Collections.reverseOrder(dbMapCompartor), // reverse
// order
// comparator
Serializer.BASIC);
String randomString = randomString(10);
BTreeMap<K, VV> make = getDB().createTreeMap("map" + randomString).pumpSource(sortIterator, valueExtractor) //$NON-NLS-1$
.keySerializer(talendBasicKeySerializer).comparator(dbMapCompartor).valueSerializer(talendSerializerBase)
.makeOrGet();
return make;
}
/**
*
* Generate a random string
*
* @param size the length of the string
* @return
*/
public String randomString(int size) {
String chars = "0123456789abcdefghijklmnopqrstuvwxyz !@#$%^&*()_+=-{}[]:\",./<>?|\\"; //$NON-NLS-1$
StringBuilder b = new StringBuilder(size);
Random r = new Random();
for (int i = 0; i < size; i++) {
b.append(chars.charAt(r.nextInt(chars.length())));
}
return b.toString();
}
/*
* (non-Javadoc)
*
* @see java.util.Map#size()
*/
@Override
public int size() {
return dbMap.size();
}
/*
* (non-Javadoc)
*
* @see java.util.Map#isEmpty()
*/
@Override
public boolean isEmpty() {
return dbMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
if (key == null) {
return dbMap.containsKey(EMPTY);
}
return dbMap.containsKey(key);
}
/*
* (non-Javadoc)
*
* @see java.util.Map#containsValue(java.lang.Object)
*/
@Override
public boolean containsValue(Object value) {
return dbMap.containsValue(value);
}
/*
* (non-Javadoc)
*
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public V get(Object key) {
if (key == null) {
return dbMap.get(EMPTY);
}
return dbMap.get(key);
}
/*
* (non-Javadoc)
*
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public V put(K key, V value) {
if (key == null) {
return dbMap.put((K) EMPTY, value);
}
// TDQ-10833 format Date.like as :Date and Timestamp is "yyyy-MM-dd HH:MM:ss";Time is "HH:MM:ss".
if (key instanceof Date) {
if (key instanceof Time) {
return dbMap.put((K) new TalendFormatTime(((Time) key)), value);
}
return dbMap.put((K) new TalendFormatDate(((Date) key)), value);
}
return dbMap.put(key, value);
}
/*
* (non-Javadoc)
*
* @see java.util.Map#remove(java.lang.Object)
*/
@Override
public V remove(Object key) {
if (key == null) {
return dbMap.remove(EMPTY);
}
return dbMap.remove(key);
}
/*
* (non-Javadoc)
*
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
public void putAll(Map<? extends K, ? extends V> m) {
dbMap.putAll(m);
}
/*
* (non-Javadoc)
*
* @see java.util.Map#clear()
*/
@Override
public void clear() {
if (!getDB().isClosed()) {
dbMap.clear();
this.getDB().delete(mapName);
}
}
/*
* (non-Javadoc)
*
* @see java.util.Map#keySet()
*/
@Override
public NavigableSet<K> keySet() {
return dbMap.keySet();
}
/*
* (non-Javadoc)
*
* @see java.util.Map#values()
*/
@Override
public Collection<V> values() {
return dbMap.values();
}
/*
* (non-Javadoc)
*
* @see java.util.Map#entrySet()
*/
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
return dbMap.entrySet();
}
/*
* (non-Javadoc)
*
* @see java.util.AbstractMap#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
return dbMap.equals(o);
}
/*
* (non-Javadoc)
*
* @see java.util.AbstractMap#hashCode()
*/
@Override
public int hashCode() {
return dbMap.hashCode();
}
/*
* (non-Javadoc)
*
* @see java.util.AbstractMap#toString()
*/
@Override
public String toString() {
return dbMap.toString();
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentMap#putIfAbsent(java.lang.Object, java.lang.Object)
*/
@Override
public V putIfAbsent(K key, V value) {
return dbMap.putIfAbsent(key, value);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentMap#remove(java.lang.Object, java.lang.Object)
*/
@Override
public boolean remove(Object key, Object value) {
return dbMap.remove(key, value);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentMap#replace(java.lang.Object, java.lang.Object, java.lang.Object)
*/
@Override
public boolean replace(K key, V oldValue, V newValue) {
return dbMap.replace(key, oldValue, newValue);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentMap#replace(java.lang.Object, java.lang.Object)
*/
@Override
public V replace(K key, V value) {
return dbMap.replace(key, value);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#lowerEntry(java.lang.Object)
*/
@Override
public java.util.Map.Entry<K, V> lowerEntry(K key) {
return dbMap.lowerEntry(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#lowerKey(java.lang.Object)
*/
@Override
public K lowerKey(K key) {
return dbMap.lowerKey(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#floorEntry(java.lang.Object)
*/
@Override
public java.util.Map.Entry<K, V> floorEntry(K key) {
return dbMap.floorEntry(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#floorKey(java.lang.Object)
*/
@Override
public K floorKey(K key) {
return dbMap.floorKey(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#ceilingEntry(java.lang.Object)
*/
@Override
public java.util.Map.Entry<K, V> ceilingEntry(K key) {
return dbMap.ceilingEntry(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#ceilingKey(java.lang.Object)
*/
@Override
public K ceilingKey(K key) {
return dbMap.ceilingKey(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#higherEntry(java.lang.Object)
*/
@Override
public java.util.Map.Entry<K, V> higherEntry(K key) {
return dbMap.higherEntry(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#higherKey(java.lang.Object)
*/
@Override
public K higherKey(K key) {
return dbMap.higherKey(key);
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#firstEntry()
*/
@Override
public java.util.Map.Entry<K, V> firstEntry() {
return dbMap.firstEntry();
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#lastEntry()
*/
@Override
public java.util.Map.Entry<K, V> lastEntry() {
return dbMap.lastEntry();
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#pollFirstEntry()
*/
@Override
public java.util.Map.Entry<K, V> pollFirstEntry() {
return dbMap.pollFirstEntry();
}
/*
* (non-Javadoc)
*
* @see java.util.NavigableMap#pollLastEntry()
*/
@Override
public java.util.Map.Entry<K, V> pollLastEntry() {
return dbMap.pollLastEntry();
}
/*
* (non-Javadoc)
*
* @see java.util.SortedMap#comparator()
*/
@Override
public Comparator<? super K> comparator() {
return dbMap.comparator();
}
/*
* (non-Javadoc)
*
* @see java.util.SortedMap#firstKey()
*/
@Override
public K firstKey() {
return dbMap.firstKey();
}
/*
* (non-Javadoc)
*
* @see java.util.SortedMap#lastKey()
*/
@Override
public K lastKey() {
return dbMap.lastKey();
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#subMap(java.lang.Object, boolean, java.lang.Object, boolean)
*/
@Override
public ConcurrentNavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
return dbMap.subMap(fromKey, fromInclusive, toKey, toInclusive);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#headMap(java.lang.Object, boolean)
*/
@Override
public ConcurrentNavigableMap<K, V> headMap(K toKey, boolean inclusive) {
return dbMap.headMap(toKey, inclusive);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#tailMap(java.lang.Object, boolean)
*/
@Override
public ConcurrentNavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
return dbMap.tailMap(fromKey, inclusive);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#subMap(java.lang.Object, java.lang.Object)
*/
@Override
public ConcurrentNavigableMap<K, V> subMap(K fromKey, K toKey) {
return dbMap.subMap(fromKey, toKey);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#headMap(java.lang.Object)
*/
@Override
public ConcurrentNavigableMap<K, V> headMap(K toKey) {
return dbMap.headMap(toKey);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#tailMap(java.lang.Object)
*/
@Override
public ConcurrentNavigableMap<K, V> tailMap(K fromKey) {
return dbMap.tailMap(fromKey);
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#descendingMap()
*/
@Override
public ConcurrentNavigableMap<K, V> descendingMap() {
return dbMap.descendingMap();
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#navigableKeySet()
*/
@Override
public NavigableSet<K> navigableKeySet() {
return dbMap.navigableKeySet();
}
/*
* (non-Javadoc)
*
* @see java.util.concurrent.ConcurrentNavigableMap#descendingKeySet()
*/
@Override
public NavigableSet<K> descendingKeySet() {
return dbMap.descendingKeySet();
}
/*
* (non-Javadoc)
*
* @see org.talend.commons.MapDB.utils.AbstractDB#tailSet(java.lang.Object, boolean)
*/
@Override
public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
return dbMap.keySet().tailSet(fromElement, inclusive);
}
/*
* (non-Javadoc)
*
* @see org.talend.commons.MapDB.utils.AbstractDB#headSet(java.lang.Object, boolean)
*/
@Override
public NavigableSet<K> headSet(K toElement, boolean inclusive) {
return dbMap.keySet().headSet(toElement, inclusive);
}
/*
* (non-Javadoc)
*
* @see org.talend.commons.MapDB.utils.AbstractDB#iterator()
*/
@Override
public Iterator<K> iterator() {
return dbMap.keySet().iterator();
}
/*
* (non-Javadoc)
*
* @see org.talend.commons.MapDB.utils.AbstractDB#subSet(java.lang.Object, java.lang.Object)
*/
@Override
public NavigableSet<K> subSet(K fromElement, K toElement) {
return dbMap.keySet().subSet(fromElement, true, toElement, false);
}
/*
* (non-Javadoc)
*
* @see org.talend.commons.MapDB.utils.AbstractDB#subList(long, long, java.util.Map)
*/
@Override
public List<Object[]> subList(long fromIndex, long toIndex, Map<Long, K> indexMap) {
return subList(fromIndex, toIndex, indexMap, null);
}
/*
* (non-Javadoc)
*
* @see org.talend.dataquality.indicators.mapdb.AbstractDB#subList(long, long, java.util.Map,
* org.talend.cwm.indicator.DataValidation)
*/
@Override
public List<Object[]> subList(long fromIndex, long toIndex, Map<Long, K> indexMap, DataValidation dataValiator) {
boolean stratToRecord = false;
List<Object[]> returnList = new ArrayList<Object[]>();
if (!checkIndex(fromIndex, toIndex)) {
return returnList;
}
K fromKey = null;
K toKey = null;
if (indexMap != null) {
fromKey = indexMap.get(fromIndex);
toKey = indexMap.get(toIndex);
}
Iterator<K> iterator = null;
long index = 0l;
if (fromKey == null) {
iterator = this.iterator();
} else if (toKey == null) {
NavigableSet<K> tailSet = tailSet(fromKey, true);
index = fromIndex;
iterator = tailSet.iterator();
} else {
NavigableSet<K> tailSet = subSet(fromKey, toKey);
index = fromIndex;
iterator = tailSet.iterator();
}
while (iterator.hasNext()) {
K next = iterator.next();
if (dataValiator != null) {
V v = this.get(next);
if (!dataValiator.isValid(v)) {
continue;
}
}
if (index == 0 && fromKey == null && indexMap != null) {
indexMap.put(0l, next);
}
if (index == fromIndex) {
stratToRecord = true;
}
if (index == toIndex) {
if (toKey == null && indexMap != null) {
indexMap.put(toIndex, next);
}
break;
}
if (stratToRecord == true) {
V v = this.get(next);
if (v.getClass().isArray()) {
returnList.add((Object[]) v);
} else if (List.class.isInstance(v)) {
returnList.add(((List<?>) v).toArray());
} else {
returnList.add(new Object[] { v });
}
}
index++;
}
return returnList;
}
}