/*
* Copyright (C) 2014 Civilian Framework.
*
* Licensed under the Civilian License (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.civilian-framework.org/license.txt
*
* 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 org.civilian.internal.asset;
import java.util.concurrent.ConcurrentHashMap;
import org.civilian.asset.Asset;
import org.civilian.asset.AssetService;
import org.civilian.content.ContentTypeLookup;
import org.civilian.internal.Logs;
import org.civilian.resource.Path;
import org.civilian.util.Check;
/**
* AssetCache maintains a cache for assets.
*/
public class AssetCache extends AssetService
{
/**
* Creates a new AssetCache.
* @param implementation provides assets if they are not yet cached.
* @param maxMemSize if the size of an Asset is smaller than maxMemSize
* than its contents will be held in memory.
*/
public AssetCache(AssetService implementation, int maxMemSize)
{
implementation_ = Check.notNull(implementation, "implementation");
maxMemSize_ = maxMemSize;
}
/**
* Forwards to the implementation.
*/
@Override public void init(Path parentPath, String defaultEncoding, ContentTypeLookup lookup)
{
implementation_.init(parentPath, defaultEncoding, lookup);
}
/**
* Returns the path of the AssetService implementation.
*/
@Override public Path getPath()
{
return implementation_.getPath();
}
/**
* Returns the path of the AssetService implementation.
*/
@Override public Path getRelativePath()
{
return implementation_.getRelativePath();
}
/**
* Forwards to the implementation.
*/
@Override public boolean hasAssets()
{
return implementation_.hasAssets();
}
/**
* Returns the Asset. It looks up the cache and if not found
* or invalid, asks the implementation to provide the asset.
*/
@Override public Asset getAsset(Path assetPath) throws Exception
{
Asset asset = getCachedAsset(assetPath);
if (asset == null)
asset = findAsset(assetPath);
return asset;
}
private Asset getCachedAsset(Path assetPath)
{
String key = assetPath.toString();
Asset asset = cache_.get(key);
if (asset != null)
{
if (!asset.isValid())
{
cache_.remove(key);
asset = null;
}
else if (Logs.ASSET.isTraceEnabled())
Logs.ASSET.trace("{} cached", assetPath);
}
return asset;
}
private Asset findAsset(Path assetPath) throws Exception
{
Asset asset = implementation_.getAsset(assetPath);
if (asset != null)
{
if (asset.length() <= maxMemSize_)
asset.readContent();
Asset oldAsset = cache_.putIfAbsent(assetPath.toString(), asset);
if (oldAsset != null)
asset = oldAsset;
}
return asset;
}
/**
* Returns an info string.
*/
@Override public String getInfo()
{
return "AssetCache[maxMem=" + maxMemSize_ + "]\n" + implementation_.getInfo();
}
private int maxMemSize_;
private AssetService implementation_;
private ConcurrentHashMap<String,Asset> cache_ = new ConcurrentHashMap<>();
}