/* * Copyright 2014 astamuse company,Ltd. * * 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.astamuse.asta4d.util; import java.lang.ref.SoftReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * We want to cache the result of not found resources but a potential DDOS attack can be performed against this wish. Thus we cache the not * found results in a SoftRreferenced map. * * @author e-ryu * * @param <K> * @param <V> */ public class MemorySafeResourceCache<K, V> { public static class ResouceHolder<T> { private T resource; ResouceHolder(T _res) { resource = _res; } public T get() { return resource; } public boolean exists() { return resource != null; } } private Map<K, ResouceHolder<V>> existingResourceMap; private SoftReference<Map<K, ResouceHolder<V>>> notExistingResourceMapRef = null; private final ResouceHolder<V> notExistingHolder = new ResouceHolder<>(null); public MemorySafeResourceCache() { // a copy on write map would be better existingResourceMap = new ConcurrentHashMap<>(); } /** * * @param key * throw NullPointerException when key is null * @param resource * null means the resource of the given key is not existing */ public void put(K key, V resource) { if (key == null) { throw new NullPointerException(); } if (resource == null) { getNotExistingResourceMap().put(key, notExistingHolder); } else { existingResourceMap.put(key, new ResouceHolder<>(resource)); } } private Map<K, ResouceHolder<V>> getNotExistingResourceMap() { Map<K, ResouceHolder<V>> map = null; if (notExistingResourceMapRef == null) { map = new ConcurrentHashMap<>(); notExistingResourceMapRef = new SoftReference<>(map); } else { map = notExistingResourceMapRef.get(); if (map == null) { map = new ConcurrentHashMap<>(); notExistingResourceMapRef = new SoftReference<>(map); } } return map; } public ResouceHolder<V> get(K key) { ResouceHolder<V> holder = existingResourceMap.get(key); if (holder == null) { holder = getNotExistingResourceMap().get(key); } return holder; } }