blob: 130e97fa41df7d209e6c9feb67c3cbc906351eea [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.openjpa.datacache;
import java.util.BitSet;
import org.apache.openjpa.kernel.AbstractPCData;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.PCData;
import org.apache.openjpa.kernel.PCDataImpl;
import org.apache.openjpa.kernel.PCState;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueMetaData;
/**
* Specialized {@link PCData} implementation for data caching. This
* implementation is properly synchronized.
*
* @author Patrick Linskey
*/
public class DataCachePCDataImpl
extends PCDataImpl
implements DataCachePCData {
private final long _exp;
/**
* Constructor.
*/
public DataCachePCDataImpl(Object oid, ClassMetaData meta) {
super(oid, meta);
int timeout = meta.getDataCacheTimeout();
if (timeout > 0)
_exp = System.currentTimeMillis() + timeout;
else
_exp = -1;
}
public boolean isTimedOut() {
return _exp != -1 && _exp < System.currentTimeMillis();
}
public synchronized Object getData(int index) {
return super.getData(index);
}
public synchronized void setData(int index, Object val) {
super.setData(index, val);
}
public synchronized void clearData(int index) {
super.clearData(index);
}
public synchronized Object getImplData() {
return super.getImplData();
}
public synchronized void setImplData(Object val) {
super.setImplData(val);
}
public synchronized Object getImplData(int index) {
return super.getImplData(index);
}
public synchronized void setImplData(int index, Object val) {
super.setImplData(index, val);
}
public synchronized Object getIntermediate(int index) {
return super.getIntermediate(index);
}
public synchronized void setIntermediate(int index, Object val) {
super.setIntermediate(index, val);
}
public synchronized boolean isLoaded(int index) {
return super.isLoaded(index);
}
public synchronized void setLoaded(int index, boolean loaded) {
super.setLoaded(index, loaded);
}
public synchronized Object getVersion() {
return super.getVersion();
}
public synchronized void setVersion(Object version) {
super.setVersion(version);
}
public synchronized void store(OpenJPAStateManager sm) {
super.store(sm);
}
public synchronized void store(OpenJPAStateManager sm, BitSet fields) {
super.store(sm, fields);
}
/**
* Store field-level information from the given state manager.
* Special process of checking if the cached collection data is out of order.
*/
protected void storeField(OpenJPAStateManager sm, FieldMetaData fmd) {
if (fmd.getManagement() != fmd.MANAGE_PERSISTENT)
return;
int index = fmd.getIndex();
// if the field is a collection and has "order by" set, don't cache
// it if this store is coming from a create or update (i.e., only
// enlist in cache if this is coming from a database read).
if (fmd.getOrders().length > 0) {
if (sm.getPCState() == PCState.PNEW)
return;
if (sm.getPCState() == PCState.PDIRTY) {
clearData(index);
return;
}
}
super.storeField(sm, fmd);
// If this field is used in "order by", we need to invalidate cache
// for the collection that refer to this field.
if ((sm.getPCState() == PCState.PDIRTY) && fmd.isUsedInOrderBy()) {
clearInverseRelationCache(sm, fmd);
}
}
/**
* Check if this field is in use of "order by" by other field collections
* in inverse relation. If it is, clear the other field cache because it
* could be out of order.
*/
protected void clearInverseRelationCache(OpenJPAStateManager sm,
FieldMetaData fmd) {
ClassMetaData cmd = sm.getMetaData();
FieldMetaData[] fields = cmd.getFields();
for (int i = 0; i < fields.length; i++) {
FieldMetaData[] inverses = fields[i].getInverseMetaDatas();
if (inverses.length == 0)
continue;
for (int j = 0; j < inverses.length; j++) {
if (inverses[j].getOrderDeclaration()
.indexOf(fmd.getName()) != -1) {
DataCache cache = sm.getMetaData().getDataCache();
Object oid = sm.getContext().getObjectId(sm.fetch(i));
DataCachePCData data = cache == null ? null
: cache.get(oid);
if ((data != null) &&
(data instanceof DataCachePCDataImpl)) {
((DataCachePCDataImpl) data)
.clearData(inverses[j].getIndex());
}
}
}
}
}
protected Object toData(FieldMetaData fmd, Object val, StoreContext ctx) {
// avoid caching large result set fields
if (fmd.isLRS() || fmd.isStream())
return NULL;
return super.toData(fmd, val, ctx);
}
protected Object toNestedData(ValueMetaData vmd, Object val,
StoreContext ctx) {
if (val == null)
return null;
// don't try to cache nested containers
switch (vmd.getDeclaredTypeCode()) {
case JavaTypes.COLLECTION:
case JavaTypes.MAP:
case JavaTypes.ARRAY:
return NULL;
default:
return super.toNestedData(vmd, val, ctx);
}
}
public AbstractPCData newEmbeddedPCData(OpenJPAStateManager sm) {
return new DataCachePCDataImpl(sm.getId(), sm.getMetaData());
}
}