/*
* Created on Oct 12, 2006 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
* (jactr.org) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have
* received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jactr.core.module.declarative.search.map;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javolution.util.FastList;
import javolution.util.FastMap;
import javolution.util.FastSet;
import javolution.util.FastTable;
import org.apache.commons.collections.collection.CompositeCollection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.utils.collections.CompositeCollectionFactory;
public class DefaultValueMap<V, I> implements IValueMap<V, I>
{
/**
* logger definition
*/
static public final Log LOGGER = LogFactory
.getLog(DefaultValueMap.class);
private ReentrantReadWriteLock _lock;
private Map<V, Collection<I>> _map;
public DefaultValueMap()
{
_lock = new ReentrantReadWriteLock();
_map = instantiateCoreMap();
}
protected ReentrantReadWriteLock getLock()
{
return _lock;
}
protected Map<V, Collection<I>> getCoreMap()
{
return _map;
}
// protected Collection<I> instantiateReturnCollection()
// {
// return FastTable.newInstance();
// }
protected CompositeCollection instantiateReturnSet()
{
return CompositeCollectionFactory.newInstance();
}
/**
* override to provide a sorted map
*
* @return
*/
protected Map<V, Collection<I>> instantiateCoreMap()
{
FastMap<V, Collection<I>> rtn = FastMap.newInstance();
// rtn.setKeyComparator(FastComparator.DIRECT);
return rtn;
// return new HashMap<V, Collection<I>>();
}
/**
* override to change the underlying collection currently HashSet
*/
protected Collection<I> instantiateCoreCollection(V forValue)
{
/*
* cant be a set since a chunk can point to this value multiple times
*/
return FastList.newInstance();
// return new HashSet<I>();
}
public void add(V value, I indexable)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
ReentrantReadWriteLock lock = getLock();
try
{
lock.writeLock().lock();
Collection<I> indexables = getCoreMap().get(value);
if (indexables == null)
{
indexables = instantiateCoreCollection(value);
getCoreMap().put(value, indexables);
}
indexables.add(indexable);
}
finally
{
lock.writeLock().unlock();
}
}
public void clear(V value)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
ReentrantReadWriteLock lock = getLock();
try
{
lock.writeLock().lock();
Collection<I> indexables = getCoreMap().remove(value);
if (indexables != null) indexables.clear();
}
finally
{
lock.writeLock().unlock();
}
}
public void clear()
{
ReentrantReadWriteLock lock = getLock();
try
{
lock.writeLock().lock();
getCoreMap().clear();
}
finally
{
lock.writeLock().unlock();
}
}
@SuppressWarnings("rawtypes")
protected void recycleCollection(Collection<I> container)
{
if (container instanceof FastList)
FastList.recycle((FastList) container);
else if (container instanceof FastSet)
FastSet.recycle((FastSet) container);
else if (container instanceof FastTable)
FastTable.recycle((FastTable) container);
}
public Collection<I> equalTo(V value)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
ReentrantReadWriteLock lock = getLock();
try
{
lock.readLock().lock();
Collection<I> indexables = getCoreMap().get(value);
if (indexables != null)
return Collections.unmodifiableCollection(indexables);
return Collections.EMPTY_LIST;
}
finally
{
lock.readLock().unlock();
}
}
public long equalToSize(V value)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
ReentrantReadWriteLock lock = getLock();
try
{
lock.readLock().lock();
Collection<I> indexables = getCoreMap().get(value);
long rtn = 0;
if (indexables != null) rtn = indexables.size();
return rtn;
}
finally
{
lock.readLock().unlock();
}
}
public Collection<I> greaterThan(V value)
throws UnsupportedOperationException
{
throw new UnsupportedOperationException(
"Since natural ordering cannot be inferred, greaterThan is not implemented");
}
public long greaterThanSize(V value) throws UnsupportedOperationException
{
throw new UnsupportedOperationException(
"Since natural ordering cannot be inferred, greaterThan is not implemented");
}
public Collection<I> lessThan(V value) throws UnsupportedOperationException
{
throw new UnsupportedOperationException(
"Since natural ordering cannot be inferred, lessthan is not implemented");
}
public long lessThanSize(V value) throws UnsupportedOperationException
{
throw new UnsupportedOperationException(
"Since natural ordering cannot be inferred, lessthan is not implemented");
}
@SuppressWarnings("unchecked")
public Collection<I> not(V value)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
CompositeCollection rtn = instantiateReturnSet();
ReentrantReadWriteLock lock = getLock();
try
{
lock.readLock().lock();
Map<V, Collection<I>> coreMap = getCoreMap();
for (V tmpValue : coreMap.keySet())
if (!tmpValue.equals(value))
{
Collection<I> get = equalTo(tmpValue);
rtn.addComposited(get);
// no longer a copy, no need to recycle
// recycleCollection(get);
}
return rtn;
}
finally
{
lock.readLock().unlock();
}
}
public long notSize(V value)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
long rtn = 0;
ReentrantReadWriteLock lock = getLock();
try
{
lock.readLock().lock();
Map<V, Collection<I>> coreMap = getCoreMap();
for (Map.Entry<V, Collection<I>> entry : coreMap.entrySet())
if (!entry.getKey().equals(value)) rtn += entry.getValue().size();
return rtn;
}
finally
{
lock.readLock().unlock();
}
}
public void remove(V value, I indexable)
{
if (value == null)
throw new NullPointerException("null values are not permitted as keys");
ReentrantReadWriteLock lock = getLock();
try
{
lock.writeLock().lock();
Collection<I> indexables = getCoreMap().get(value);
if (indexables != null)
{
indexables.remove(indexable);
if (indexables.size() == 0)
{
getCoreMap().remove(value);
recycleCollection(indexables);
}
}
}
finally
{
lock.writeLock().unlock();
}
}
@SuppressWarnings("unchecked")
public Collection<I> all()
{
CompositeCollection rtn = instantiateReturnSet();
ReentrantReadWriteLock lock = getLock();
try
{
lock.readLock().lock();
for (Collection<I> values : getCoreMap().values())
rtn.addComposited(values);
return rtn;
}
finally
{
lock.readLock().unlock();
}
}
public long allSize()
{
ReentrantReadWriteLock lock = getLock();
long rtn = 0;
try
{
lock.readLock().lock();
for (Collection<I> values : getCoreMap().values())
rtn += values.size();
return rtn;
}
finally
{
lock.readLock().unlock();
}
}
}