/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* File: $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.common/src/com/ibm/adtech/boca/rdb/layout/ValueLayoutCacheProxy.java,v $
* Created by: Stephen Evanchik <evanchik@us.ibm.com>
* Created on: 9/30/2005
* Revision: $Id: ValueLayoutCacheProxy.java 178 2007-07-31 14:22:33Z mroy $
*
* Contributors:
* IBM Corporation - initial API and implementation
* C Semantics Incorporated - Fork to Anzo
*******************************************************************************/
package org.openanzo.jdbc.layout;
import java.sql.Connection;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.openanzo.cache.ICache;
import org.openanzo.jdbc.container.sql.NodeSQL.FetchAllCommonValuesResult;
import org.openanzo.jdbc.utils.ClosableIterator;
import org.openanzo.jdbc.utils.IteratorUtils;
import org.openanzo.jdbc.utils.RdbException;
/**
* Wraps and caches data accessed by an IValueLayout object.
*
* @author Joe Betz
* @author Stephen Evanchik <evanchik@us.ibm.com>
*/
public class ValueLayoutCacheProxy implements IValueLayout, ILayoutCache<String> {
private final IValueLayout base;
private final ICache<Long, String> cache;
private final ICache<String, Long> idCache;
private final Map<Long, String> uncommitedByIdCache;
private final Map<String, Long> uncommitedByValueCache;
/**
* Create Cache Proxy for the given base layout.
*
* @param base
* Base layout to add caching layer onto
* @param byIdCache
* ID cache for this layout
* @param byValueCache
* Value cache for this layout
*/
protected ValueLayoutCacheProxy(IValueLayout base, ICache<Long, String> cache, ICache<String, Long> idCache) {
this.base = base;
this.cache = cache;
this.idCache = idCache;
uncommitedByIdCache = Collections.synchronizedMap(new HashMap<Long, String>());
uncommitedByValueCache = Collections.synchronizedMap(new HashMap<String, Long>());
}
public void clearCache() {
cache.clear();
idCache.clear();
uncommitedByIdCache.clear();
uncommitedByValueCache.clear();
}
public void commitUncommittedCache() {
for (Map.Entry<String, Long> entry : uncommitedByValueCache.entrySet()) {
idCache.put(entry.getKey(), entry.getValue());
}
for (Map.Entry<Long, String> entry : uncommitedByIdCache.entrySet()) {
cache.put(entry.getKey(), entry.getValue());
}
uncommitedByValueCache.clear();
uncommitedByIdCache.clear();
}
public void clearUncommittedCache() {
uncommitedByValueCache.clear();
uncommitedByIdCache.clear();
}
void addToCache(Long id, String value) {
uncommitedByIdCache.put(id, value);
uncommitedByValueCache.put(value, id);
}
public String cache(Long id, String value, Long modifierId, Connection connection) {
return null;
}
public boolean isCached(String value) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
return uncommitedByValueCache.containsKey(value) || idCache.get(value) != null;
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
public boolean isCached(Long id) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
return uncommitedByIdCache.containsKey(id) || cache.get(id) != null;
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
public Long getIfCached(String value) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
Long id = uncommitedByValueCache.get(value);
if (id == null) {
id = idCache.get(value);
}
return id;
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
public String getIfCached(Long id) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
String obj = uncommitedByIdCache.get(id);
if (obj == null) {
obj = cache.get(id);
}
return obj;
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
public Long fetchId(String value, Connection connection) throws RdbException {
Long id = getIfCached(value);
if (id != null) {
return id;
}
id = base.fetchId(value, connection);
if (id == null) {
return null;
}
addToCache(id, value);
return id;
}
public String fetchValue(Long id, Connection connection) throws RdbException {
String value = getIfCached(id);
if (value != null) {
return value;
}
value = base.fetchValue(id, connection);
if (value == null) {
return null;
}
addToCache(id, value);
return value;
}
public Long store(String value, Connection connection) throws RdbException {
Long id = getIfCached(value);
if (id != null) {
return id;
}
id = base.store(value, connection);
addToCache(id, value);
return id;
}
/**
* Doesn't cached added nodes
*/
public void batchAdd(Collection<String> iter, Connection connection) throws RdbException {
base.batchAdd(iter, connection);
}
/**
* Doesn't cache fetched Nodes
*/
public ClosableIterator<FetchAllCommonValuesResult> fetchAll(Connection connection) throws RdbException {
return base.fetchAll(connection);
}
/**
* Add set of strings into this layout and cache their values
*
* @param connection
* connection to jdbc database to which data is added
* @param iter
* set of strings to store and cache
* @throws RdbException
*/
public void batchAddAndCache(Collection<String> iter, Connection connection) throws RdbException {
base.batchAdd(iter, connection);
ClosableIterator<FetchAllCommonValuesResult> cIter = base.fetchAll(connection);
try {
while (cIter.hasNext()) {
FetchAllCommonValuesResult result = cIter.next();
String value = result.getValue();
Long id = Long.valueOf(result.getId());
addToCache(id, value);
}
} finally {
IteratorUtils.close(cIter);
}
}
}