All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minidev.util.CachedMapper Maven / Gradle / Ivy

The newest version!
package net.minidev.util;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * A single or dual Way Cached mapping table
 * 
 * Datas may expire by timeout, or by a Max buffer Size
 * 
 * @author Uriel Chemouni
 * 
 * @param 
 *            Key
 * @param 
 *            Value
 */
public class CachedMapper {
	protected final Queue> data;
	protected final HashMap index1;
	protected final HashMap index2;

	protected final long TTL;
	protected final int maxSize;

	private static CacheCleaner cleaner = new CacheCleaner();

	public static void destroy() {
		CacheCleaner cc = cleaner;
		if (cc != null)
			synchronized (cc.maps) {
				cc.maps.clear();
			}
	}

	public static enum CacheType {
		SINGLE, DUAL
	}

	/**
	 * create a CacheMapper
	 * 
	 * @param type SINGLE or DUAL
	 * @param time in millisec
	 */
	public CachedMapper(CacheType type, long time) {
		this(type, time, 10000);
	}

	/**
	 * create a CacheMapper
	 * 
	 * @param type SINGLE or DUAL
	 * @param time in millisec
	 * @param size cache capacity in object
	 */
	public CachedMapper(CacheType type, long time, int size) {
		synchronized (this.getClass()) {
			if (cleaner == null)
				cleaner = new CacheCleaner();
		}
		this.TTL = time;
		if (size < 1)
			throw new java.lang.IllegalArgumentException("Size must be > 0");
		this.maxSize = size;

		data = new LinkedBlockingQueue>();
		index1 = new HashMap();
		if (type == CacheType.DUAL)
			index2 = new HashMap();
		else
			index2 = null;

		cleaner.addMap(this);
	}

	public V get(K key) {
		return index1.get(key);
	}

	public K getRev(V value) {
		if (index2 != null)
			return index2.get(value);
		else
			throw new RuntimeException("to use CachedMapper Rev mapping, build ChachedMapper With CacheType.DUAL FLAG");
	}

	public void put(K key, V value) {
		TimedData ent = new TimedData(key, value);
		synchronized (data) {
			data.add(ent);
			index1.put(key, value);
			if (index2 != null)
				index2.put(value, key);
		}
	}

	public void remove(K key) {
		synchronized (data) {
			V value = index1.remove(key);
			if (index2 != null && value != null)
				index2.remove(value);
		}
	}

	public void clear() {
		synchronized (data) {
			data.clear();
			index1.clear();
			if (index2 != null)
				index2.clear();
		}
	}

	public static class TimedData {
		public long time;
		public K key;
		public V value;

		public TimedData(K key, V value) {
			this.time = System.currentTimeMillis();
			this.key = key;
			this.value = value;
		}
	}

	static class CacheCleaner extends TimerTask {
		final LinkedList>> maps;

		public CacheCleaner() {
			maps = new LinkedList>>();
			StaticTimer.schedule(this, 3000, 3000);
		}

		public void addMap(CachedMapper map) {
			synchronized (maps) {
				maps.add(new WeakReference>(map));
			}
		}

		private void pass() {
			synchronized (maps) {
				Iterator>> iter;
				iter = maps.iterator();
				while (iter.hasNext()) {
					WeakReference> ref = iter.next();
					CachedMapper map = ref.get();
					if (map == null) {
						iter.remove();
						continue;
					}
					long timeOut = System.currentTimeMillis() - map.TTL;
					TimedData entry;
					final Queue data = map.data;
					synchronized (data) {
						// Filtrage par TTL
						entry = (TimedData) data.peek();
						while (entry != null && entry.time < timeOut) {
							TimedData ttData = (TimedData) data.poll();
							map.index1.remove(ttData.key);
							if (map.index2 != null)
								map.index2.remove(ttData.value);
							entry = (TimedData) data.peek();
						}

						// Filtrage par Max Size
						if (data.size() > map.maxSize) {
							int toRemove = data.size() - map.maxSize;
							while (toRemove-- > 0) {
								TimedData ttData = (TimedData) data.poll();
								map.index1.remove(ttData.key);
								if (map.index2 != null)
									map.index2.remove(ttData.value);
							}
						}
					}
				}
			}
		}

		public void run() {
			pass();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy