001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.datacache;
020:
021: import java.util.BitSet;
022:
023: import org.apache.openjpa.kernel.AbstractPCData;
024: import org.apache.openjpa.kernel.OpenJPAStateManager;
025: import org.apache.openjpa.kernel.PCData;
026: import org.apache.openjpa.kernel.PCDataImpl;
027: import org.apache.openjpa.kernel.PCState;
028: import org.apache.openjpa.kernel.StoreContext;
029: import org.apache.openjpa.meta.ClassMetaData;
030: import org.apache.openjpa.meta.FieldMetaData;
031: import org.apache.openjpa.meta.JavaTypes;
032: import org.apache.openjpa.meta.ValueMetaData;
033:
034: /**
035: * Specialized {@link PCData} implementation for data caching. This
036: * implementation is properly synchronized.
037: *
038: * @author Patrick Linskey
039: */
040: public class DataCachePCDataImpl extends PCDataImpl implements
041: DataCachePCData {
042:
043: private final long _exp;
044:
045: /**
046: * Constructor.
047: */
048: public DataCachePCDataImpl(Object oid, ClassMetaData meta) {
049: super (oid, meta);
050:
051: int timeout = meta.getDataCacheTimeout();
052: if (timeout > 0)
053: _exp = System.currentTimeMillis() + timeout;
054: else
055: _exp = -1;
056: }
057:
058: public boolean isTimedOut() {
059: return _exp != -1 && _exp < System.currentTimeMillis();
060: }
061:
062: public synchronized Object getData(int index) {
063: return super .getData(index);
064: }
065:
066: public synchronized void setData(int index, Object val) {
067: super .setData(index, val);
068: }
069:
070: public synchronized void clearData(int index) {
071: super .clearData(index);
072: }
073:
074: public synchronized Object getImplData() {
075: return super .getImplData();
076: }
077:
078: public synchronized void setImplData(Object val) {
079: super .setImplData(val);
080: }
081:
082: public synchronized Object getImplData(int index) {
083: return super .getImplData(index);
084: }
085:
086: public synchronized void setImplData(int index, Object val) {
087: super .setImplData(index, val);
088: }
089:
090: public synchronized Object getIntermediate(int index) {
091: return super .getIntermediate(index);
092: }
093:
094: public synchronized void setIntermediate(int index, Object val) {
095: super .setIntermediate(index, val);
096: }
097:
098: public synchronized boolean isLoaded(int index) {
099: return super .isLoaded(index);
100: }
101:
102: public synchronized void setLoaded(int index, boolean loaded) {
103: super .setLoaded(index, loaded);
104: }
105:
106: public synchronized Object getVersion() {
107: return super .getVersion();
108: }
109:
110: public synchronized void setVersion(Object version) {
111: super .setVersion(version);
112: }
113:
114: public synchronized void store(OpenJPAStateManager sm) {
115: super .store(sm);
116: }
117:
118: public synchronized void store(OpenJPAStateManager sm, BitSet fields) {
119: super .store(sm, fields);
120: }
121:
122: /**
123: * Store field-level information from the given state manager.
124: * Special process of checking if the cached collection data is out of order.
125: */
126: protected void storeField(OpenJPAStateManager sm, FieldMetaData fmd) {
127: if (fmd.getManagement() != fmd.MANAGE_PERSISTENT)
128: return;
129: int index = fmd.getIndex();
130:
131: // if the field is a collection and has "order by" set, don't cache
132: // it if this store is coming from a create or update (i.e., only
133: // enlist in cache if this is coming from a database read).
134: if (fmd.getOrders().length > 0) {
135: if (sm.getPCState() == PCState.PNEW)
136: return;
137: if (sm.getPCState() == PCState.PDIRTY) {
138: clearData(index);
139: return;
140: }
141: }
142:
143: super .storeField(sm, fmd);
144:
145: // If this field is used in "order by", we need to invalidate cache
146: // for the collection that refer to this field.
147: if ((sm.getPCState() == PCState.PDIRTY)
148: && fmd.isUsedInOrderBy()) {
149: clearInverseRelationCache(sm, fmd);
150: }
151: }
152:
153: /**
154: * Check if this field is in use of "order by" by other field collections
155: * in inverse relation. If it is, clear the other field cache because it
156: * could be out of order.
157: */
158: protected void clearInverseRelationCache(OpenJPAStateManager sm,
159: FieldMetaData fmd) {
160: ClassMetaData cmd = sm.getMetaData();
161: FieldMetaData[] fields = cmd.getFields();
162: for (int i = 0; i < fields.length; i++) {
163: FieldMetaData[] inverses = fields[i].getInverseMetaDatas();
164: if (inverses.length == 0)
165: continue;
166: for (int j = 0; j < inverses.length; j++) {
167: if (inverses[j].getOrderDeclaration().indexOf(
168: fmd.getName()) != -1) {
169: DataCache cache = sm.getMetaData().getDataCache();
170: Object oid = sm.getContext().getObjectId(
171: sm.fetch(i));
172: DataCachePCData data = cache == null ? null : cache
173: .get(oid);
174: if ((data != null)
175: && (data instanceof DataCachePCDataImpl)) {
176: ((DataCachePCDataImpl) data)
177: .clearData(inverses[j].getIndex());
178: }
179: }
180: }
181: }
182: }
183:
184: protected Object toData(FieldMetaData fmd, Object val,
185: StoreContext ctx) {
186: // avoid caching large result set fields
187: if (fmd.isLRS() || fmd.isStream())
188: return NULL;
189: return super .toData(fmd, val, ctx);
190: }
191:
192: protected Object toNestedData(ValueMetaData vmd, Object val,
193: StoreContext ctx) {
194: if (val == null)
195: return null;
196:
197: // don't try to cache nested containers
198: switch (vmd.getDeclaredTypeCode()) {
199: case JavaTypes.COLLECTION:
200: case JavaTypes.MAP:
201: case JavaTypes.ARRAY:
202: return NULL;
203: default:
204: return super .toNestedData(vmd, val, ctx);
205: }
206: }
207:
208: public AbstractPCData newEmbeddedPCData(OpenJPAStateManager sm) {
209: return new DataCachePCDataImpl(sm.getId(), sm.getMetaData());
210: }
211: }
|