/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 net.ontopia.persistence.proxy;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* INTERNAL: A transactional storage cache implementation. The cache
* uses the transaction to lookup objects and relies on the fact that
* PersistentIFs can store their own data.
*/
public abstract class AbstractLocalCache implements StorageCacheIF, AccessRegistrarIF {
// Define a logging category.
static Logger log = LoggerFactory.getLogger(AbstractLocalCache.class.getName());
protected AbstractTransaction txn;
protected StorageCacheIF pcache;
protected AccessRegistrarIF pregistrar;
protected TicketIF ticket;
AbstractLocalCache(AbstractTransaction txn, StorageCacheIF pcache) {
this.txn = txn;
this.pcache = pcache;
if (this.pcache != null)
this.pregistrar = this.pcache.getRegistrar();
else {
this.ticket = new TicketIF() {
public boolean isValid() {
return true;
}
};
}
}
// -----------------------------------------------------------------------------
// StorageCacheIF implementation
// -----------------------------------------------------------------------------
public AccessRegistrarIF getRegistrar() {
return this;
}
public void close() {
}
public abstract boolean exists(StorageAccessIF access, IdentityIF identity);
public abstract Object getValue(StorageAccessIF access, IdentityIF identity, int field);
public boolean isObjectLoaded(IdentityIF identity) {
if (pcache != null)
return pcache.isObjectLoaded(identity);
return false;
}
public boolean isFieldLoaded(IdentityIF identity, int field) {
if (pcache != null)
return pcache.isFieldLoaded(identity, field);
return false;
}
// -----------------------------------------------------------------------------
// eviction
// -----------------------------------------------------------------------------
public void registerEviction() {
if (pcache != null) pcache.registerEviction();
}
public void releaseEviction() {
if (pcache != null) pcache.releaseEviction();
}
public void evictIdentity(IdentityIF identity, boolean notifyCluster) {
if (pcache != null) pcache.evictIdentity(identity, notifyCluster);
}
public void evictFields(IdentityIF identity, boolean notifyCluster) {
if (pcache != null) pcache.evictFields(identity, notifyCluster);
}
public void evictField(IdentityIF identity, int field, boolean notifyCluster) {
if (pcache != null) pcache.evictField(identity, field, notifyCluster);
}
public void clear(boolean notifyCluster) {
if (pcache != null) pcache.clear(notifyCluster);
}
// -----------------------------------------------------------------------------
// prefetch
// -----------------------------------------------------------------------------
// ISSUE: prefetch locally if no parent cache?
public int prefetch(StorageAccessIF access, Class<?> type, int field, int nextField, boolean traverse, Collection<IdentityIF> identities) {
// WARNING: dirty objects should never be handed over to shared cache
if (pcache != null) return pcache.prefetch(access, type, field, nextField, traverse, identities);
return 0;
}
// -----------------------------------------------------------------------------
// AccessRegistrarIF implementation
// -----------------------------------------------------------------------------
public IdentityIF createIdentity(Class<?> type, long key) {
return new LongIdentity(type, key);
}
public IdentityIF createIdentity(Class<?> type, Object key) {
return new AtomicIdentity(type, key);
}
public IdentityIF createIdentity(Class<?> type, Object[] keys) {
return new Identity(type, keys);
}
public TicketIF getTicket() {
if (pregistrar == null)
return ticket;
else
return pregistrar.getTicket();
}
public void registerIdentity(TicketIF ticket, IdentityIF identity) {
if (log.isDebugEnabled())
log.debug("Registering identity " + identity);
// notify parent cache if no txn changes
if (pregistrar != null && txn.isObjectClean(identity))
pregistrar.registerIdentity(ticket, identity);
// make sure txn holds an object instance
txn.checkIdentityMapAndCreateInstance(identity);
}
public void registerField(TicketIF ticket, IdentityIF identity, int field, Object value) {
if (log.isDebugEnabled())
log.debug("Registering " + identity + " field " + field + "=" + value);
// notify parent cache if no txn changes
if (pregistrar != null && txn.isObjectClean(identity))
pregistrar.registerField(ticket, identity, field, value);
// make sure txn holds an object instance
txn.checkIdentityMapAndCreateInstance(identity);
}
}