/*
* Copyright 2013 cruxframework.org.
*
* 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 org.cruxframework.crux.core.server.rest.state;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* It is a very basic implementation for ResourceStateHandler interface that is
* designed to run only on NO CUSTERED environment. It uses a simple LRUMap to
* keep the resource state into local machine's memory.
*
* To configure the cache, you can create a file named
* NoClusteredCacheConfig.properties and configure the property
* maxNumberOfEntries to set the max number of entries into the map.
*
* @author Thiago da Rosa de Bustamante
*
*/
public class NoClusteredResourceStateHandler implements ResourceStateHandler
{
public static class LRUMap<K, V> extends LinkedHashMap<K, V>
{
private static final long serialVersionUID = -8939312812258005339L;
private final int maxEntries;
public LRUMap(int maxEntries)
{
super(maxEntries, 0.75f, true);
this.maxEntries = maxEntries;
}
@Override
protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest)
{
return super.size() > maxEntries;
}
}
public static class CacheEntry implements ResourceState
{
private final long dateModifiedMilis;
private final long expires;
private final String etag;
private CacheEntry(long dateModifiedMilis, long expires, String etag)
{
this.dateModifiedMilis = dateModifiedMilis;
this.expires = expires;
this.etag = etag;
}
@Override
public long getDateModified()
{
return dateModifiedMilis;
}
@Override
public String getEtag()
{
return etag;
}
@Override
public boolean isExpired()
{
return System.currentTimeMillis() >= expires;
}
}
private Map<String, CacheEntry> cache;
/**
*
*/
public NoClusteredResourceStateHandler()
{
int maxCacheItems = Integer.parseInt(NoClusteredCacheConfigurationFactory.getConfigurations().maxNumberOfEntries());
cache = Collections.synchronizedMap(new LRUMap<String, CacheEntry>(maxCacheItems));
}
@Override
public ResourceState add(String uri, long dateModified, long expires, String etag)
{
CacheEntry cacheEntry = new CacheEntry(dateModified, expires, etag);
cache.put(uri, cacheEntry);
return cacheEntry;
}
@Override
public ResourceState get(String uri)
{
return cache.get(uri);
}
@Override
public void remove(String uri)
{
cache.remove(uri);
}
@Override
public void clear()
{
cache.clear();
}
@Override
public void removeSegments(String... baseURIs)
{
Set<String> keys = cache.keySet();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext())
{
String key = iterator.next();
for (String baseURI : baseURIs)
{
if (key.startsWith(baseURI))
{
iterator.remove();
break;
}
}
}
}
}