1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.datacache;
20
21 import java.util.BitSet;
22
23 import org.apache.openjpa.kernel.AbstractPCData;
24 import org.apache.openjpa.kernel.OpenJPAStateManager;
25 import org.apache.openjpa.kernel.PCData;
26 import org.apache.openjpa.kernel.PCDataImpl;
27 import org.apache.openjpa.kernel.PCState;
28 import org.apache.openjpa.kernel.StoreContext;
29 import org.apache.openjpa.meta.ClassMetaData;
30 import org.apache.openjpa.meta.FieldMetaData;
31 import org.apache.openjpa.meta.JavaTypes;
32 import org.apache.openjpa.meta.ValueMetaData;
33
34 /**
35 * Specialized {@link PCData} implementation for data caching. This
36 * implementation is properly synchronized.
37 *
38 * @author Patrick Linskey
39 */
40 public class DataCachePCDataImpl
41 extends PCDataImpl
42 implements DataCachePCData {
43
44 private final long _exp;
45
46 /**
47 * Constructor.
48 */
49 public DataCachePCDataImpl(Object oid, ClassMetaData meta) {
50 super(oid, meta);
51
52 int timeout = meta.getDataCacheTimeout();
53 if (timeout > 0)
54 _exp = System.currentTimeMillis() + timeout;
55 else
56 _exp = -1;
57 }
58
59 public boolean isTimedOut() {
60 return _exp != -1 && _exp < System.currentTimeMillis();
61 }
62
63 public synchronized Object getData(int index) {
64 return super.getData(index);
65 }
66
67 public synchronized void setData(int index, Object val) {
68 super.setData(index, val);
69 }
70
71 public synchronized void clearData(int index) {
72 super.clearData(index);
73 }
74
75 public synchronized Object getImplData() {
76 return super.getImplData();
77 }
78
79 public synchronized void setImplData(Object val) {
80 super.setImplData(val);
81 }
82
83 public synchronized Object getImplData(int index) {
84 return super.getImplData(index);
85 }
86
87 public synchronized void setImplData(int index, Object val) {
88 super.setImplData(index, val);
89 }
90
91 public synchronized Object getIntermediate(int index) {
92 return super.getIntermediate(index);
93 }
94
95 public synchronized void setIntermediate(int index, Object val) {
96 super.setIntermediate(index, val);
97 }
98
99 public synchronized boolean isLoaded(int index) {
100 return super.isLoaded(index);
101 }
102
103 public synchronized void setLoaded(int index, boolean loaded) {
104 super.setLoaded(index, loaded);
105 }
106
107 public synchronized Object getVersion() {
108 return super.getVersion();
109 }
110
111 public synchronized void setVersion(Object version) {
112 super.setVersion(version);
113 }
114
115 public synchronized void store(OpenJPAStateManager sm) {
116 super.store(sm);
117 }
118
119 public synchronized void store(OpenJPAStateManager sm, BitSet fields) {
120 super.store(sm, fields);
121 }
122
123 /**
124 * Store field-level information from the given state manager.
125 * Special process of checking if the cached collection data is out of order.
126 */
127 protected void storeField(OpenJPAStateManager sm, FieldMetaData fmd) {
128 if (fmd.getManagement() != fmd.MANAGE_PERSISTENT)
129 return;
130 int index = fmd.getIndex();
131
132 // if the field is a collection and has "order by" set, don't cache
133 // it if this store is coming from a create or update (i.e., only
134 // enlist in cache if this is coming from a database read).
135 if (fmd.getOrders().length > 0) {
136 if (sm.getPCState() == PCState.PNEW)
137 return;
138 if (sm.getPCState() == PCState.PDIRTY) {
139 clearData(index);
140 return;
141 }
142 }
143
144 super.storeField(sm, fmd);
145
146 // If this field is used in "order by", we need to invalidate cache
147 // for the collection that refer to this field.
148 if ((sm.getPCState() == PCState.PDIRTY) && 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()
168 .indexOf(fmd.getName()) != -1) {
169 DataCache cache = sm.getMetaData().getDataCache();
170 Object oid = sm.getContext().getObjectId(sm.fetch(i));
171 DataCachePCData data = cache == null ? null
172 : cache.get(oid);
173 if ((data != null) &&
174 (data instanceof DataCachePCDataImpl)) {
175 ((DataCachePCDataImpl) data)
176 .clearData(inverses[j].getIndex());
177 }
178 }
179 }
180 }
181 }
182
183 protected Object toData(FieldMetaData fmd, Object val, StoreContext ctx) {
184 // avoid caching large result set fields
185 if (fmd.isLRS() || fmd.isStream())
186 return NULL;
187 return super.toData(fmd, val, ctx);
188 }
189
190 protected Object toNestedData(ValueMetaData vmd, Object val,
191 StoreContext ctx) {
192 if (val == null)
193 return null;
194
195 // don't try to cache nested containers
196 switch (vmd.getDeclaredTypeCode()) {
197 case JavaTypes.COLLECTION:
198 case JavaTypes.MAP:
199 case JavaTypes.ARRAY:
200 return NULL;
201 default:
202 return super.toNestedData(vmd, val, ctx);
203 }
204 }
205
206 public AbstractPCData newEmbeddedPCData(OpenJPAStateManager sm) {
207 return new DataCachePCDataImpl(sm.getId(), sm.getMetaData());
208 }
209 }