/**
* License Agreement for OpenSearchServer
* <p>
* Copyright (C) 2017 Emmanuel Keller / Jaeksoft
* <p>
* http://www.open-search-server.com
* <p>
* This file is part of OpenSearchServer.
* <p>
* OpenSearchServer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* OpenSearchServer 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with OpenSearchServer.
* If not, see <http://www.gnu.org/licenses/>.
**/
package com.jaeksoft.searchlib.crawler.web;
import com.jaeksoft.searchlib.SearchLibException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class GenericCache<K, V extends GenericCache.Expirable> {
public interface Expirable {
long getExpirationTime();
boolean isCacheable();
}
public interface ItemSupplier<R extends Expirable> {
R get() throws SearchLibException, URISyntaxException, IOException;
}
private final Map<K, V> map;
private final Map<K, Object> keyLock;
protected GenericCache() {
map = new HashMap<>();
keyLock = new HashMap<>();
}
/**
* Remove the expired items (relative to the t parameter)
*
* @param t
*/
private void checkExpiration(long t) {
synchronized (map) {
final Iterator<Entry<K, V>> it = map.entrySet().iterator();
ArrayList<K> keyToRemove = null;
while (it.hasNext()) {
Entry<K, V> e = it.next();
if (t > e.getValue().getExpirationTime()) {
if (keyToRemove == null)
keyToRemove = new ArrayList<>();
keyToRemove.add(e.getKey());
}
}
if (keyToRemove != null) {
for (K key : keyToRemove) {
map.remove(key);
keyLock.remove(key);
}
}
}
}
/**
* Return the RobotsTxt object related to the URL.
*
* @param key
* @param supplier
* @param forceReload
* @return
* @throws SearchLibException
* @throws URISyntaxException
* @throws IOException
*/
final public V getOrCreate(K key, boolean forceReload, ItemSupplier<V> supplier)
throws SearchLibException, URISyntaxException, IOException {
Object lock;
synchronized (map) {
lock = keyLock.get(key);
if (lock == null) {
lock = new Object();
keyLock.put(key, lock);
}
checkExpiration(System.currentTimeMillis());
if (forceReload)
map.remove(key);
V value = map.get(key);
if (value != null)
return value;
}
synchronized (lock) {
synchronized (map) {
V value = map.get(key);
if (value != null)
return value;
}
V value = supplier.get();
synchronized (map) {
map.put(key, value);
return value;
}
}
}
final public V get(K key) {
synchronized (map) {
return map.get(key);
}
}
final public V[] getList() {
synchronized (map) {
return (V[]) map.values().toArray();
}
}
}