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.kernel;
020:
021: import java.io.Serializable;
022: import java.io.ObjectOutputStream;
023: import java.io.IOException;
024: import java.io.ObjectInputStream;
025: import java.util.BitSet;
026: import java.util.Collection;
027: import java.util.Date;
028: import java.util.Map;
029:
030: import org.apache.openjpa.enhance.PersistenceCapable;
031: import org.apache.openjpa.lib.util.Localizer;
032: import org.apache.openjpa.meta.FieldMetaData;
033: import org.apache.openjpa.meta.JavaTypes;
034: import org.apache.openjpa.util.InternalException;
035: import org.apache.openjpa.util.ProxyManager;
036:
037: /**
038: * FieldManager type used to store information for savepoint rollback.
039: *
040: * @author Steve Kim
041: * @since 0.3.4
042: */
043: class SavepointFieldManager extends ClearFieldManager implements
044: Serializable {
045:
046: private static final Localizer _loc = Localizer
047: .forPackage(SavepointFieldManager.class);
048:
049: private final StateManagerImpl _sm;
050: private final BitSet _loaded;
051: private final BitSet _dirty;
052: private final BitSet _flush;
053: private final PCState _state;
054: private transient PersistenceCapable _copy;
055:
056: private final Object _version;
057: private final Object _loadVersion;
058:
059: // used to track field value during store/fetch cycle
060: private Object _field = null;
061: private int[] _copyField = null;
062: private BitSet _mutable;
063:
064: /**
065: * Constructor. Provide instance to save and indicate whether
066: * to copy persistent fields. Transactional fields will be
067: * copied regardless of copy setting.
068: */
069: public SavepointFieldManager(StateManagerImpl sm, boolean copy) {
070: _sm = sm;
071: _state = _sm.getPCState();
072:
073: _dirty = (BitSet) _sm.getDirty().clone();
074: _flush = (BitSet) _sm.getFlushed().clone();
075: _loaded = (BitSet) _sm.getLoaded().clone();
076:
077: FieldMetaData[] fields = _sm.getMetaData().getFields();
078: for (int i = 0; i < _loaded.length(); i++) {
079: if (!_loaded.get(i))
080: continue;
081: if (copy
082: || fields[i].getManagement() == FieldMetaData.MANAGE_TRANSACTIONAL) {
083: if (_copy == null)
084: _copy = _sm.getPersistenceCapable().pcNewInstance(
085: _sm, true);
086: storeField(fields[i]);
087: } else
088: _loaded.clear(i);
089: }
090:
091: // we need to proxy the fields so that we can track future changes
092: // from this savepoint forward for PNew instances' mutable fields
093: _sm.proxyFields(false, false);
094:
095: _version = _sm.getVersion();
096: _loadVersion = _sm.getLoadVersion();
097: }
098:
099: /**
100: * Return the state manager that this manager is associated with.
101: */
102: public StateManagerImpl getStateManager() {
103: return _sm;
104: }
105:
106: public Object getVersion() {
107: return _version;
108: }
109:
110: public Object getLoadVersion() {
111: return _loadVersion;
112: }
113:
114: /**
115: * Return the persistence capable copy holding the savepoint field values.
116: */
117: public PersistenceCapable getCopy() {
118: return _copy;
119: }
120:
121: /**
122: * Return the saved {@link PCState}
123: */
124: public PCState getPCState() {
125: return _state;
126: }
127:
128: /**
129: * Return the fields stored in this manager.
130: */
131: public BitSet getLoaded() {
132: return _loaded;
133: }
134:
135: /**
136: * Return the dirty fields during the saved state.
137: */
138: public BitSet getDirty() {
139: return _dirty;
140: }
141:
142: /**
143: * Return the flushed fields during the saved state.
144: */
145: public BitSet getFlushed() {
146: return _flush;
147: }
148:
149: /**
150: * Store the data for the given field.
151: */
152: public void storeField(FieldMetaData field) {
153: switch (field.getDeclaredTypeCode()) {
154: case JavaTypes.DATE:
155: case JavaTypes.ARRAY:
156: case JavaTypes.COLLECTION:
157: case JavaTypes.MAP:
158: case JavaTypes.OBJECT:
159: if (_mutable == null)
160: _mutable = new BitSet(
161: _sm.getMetaData().getFields().length);
162: _mutable.set(field.getIndex());
163: }
164: if (_mutable == null || !_mutable.get(field.getIndex())) {
165: // immutable fields can just be copied over
166: if (_copyField == null)
167: _copyField = new int[1];
168: _copyField[0] = field.getIndex();
169: _copy.pcCopyFields(_sm.getPersistenceCapable(), _copyField);
170: } else {
171: _sm.provideField(_sm.getPersistenceCapable(), this , field
172: .getIndex());
173: _sm.replaceField(_copy, this , field.getIndex());
174: }
175: }
176:
177: /**
178: * Restore the given field. If this method returns true, then you need
179: * to use this field manager to replace the given field in the state
180: * manager's instance.
181: */
182: public boolean restoreField(int field) {
183: if (!_loaded.get(field))
184: return false;
185: if (_mutable != null && _mutable.get(field))
186: return true;
187:
188: // copy the saved field over
189: if (_copyField == null)
190: _copyField = new int[1];
191: _copyField[0] = field;
192: _sm.getPersistenceCapable().pcCopyFields(_copy, _copyField);
193: return false;
194: }
195:
196: public Object fetchObjectField(int field) {
197: // return the copied field during save, or a null value during restore
198: Object val = _field;
199: _field = null;
200: return val;
201: }
202:
203: public void storeObjectField(int field, Object curVal) {
204: // copy mutable fields
205: ProxyManager proxy = _sm.getContext().getConfiguration()
206: .getProxyManagerInstance();
207: FieldMetaData fmd = _sm.getMetaData().getField(field);
208: switch (fmd.getDeclaredTypeCode()) {
209: case JavaTypes.ARRAY:
210: _field = proxy.copyArray(curVal);
211: break;
212: case JavaTypes.COLLECTION:
213: _field = proxy.copyCollection((Collection) curVal);
214: break;
215: case JavaTypes.MAP:
216: _field = proxy.copyMap((Map) curVal);
217: break;
218: case JavaTypes.DATE:
219: _field = proxy.copyDate((Date) curVal);
220: break;
221: case JavaTypes.OBJECT:
222: _field = proxy.copyCustom(curVal);
223: if (_field == null)
224: _field = curVal;
225: break;
226: default:
227: _field = curVal;
228: }
229:
230: // if we couldn't get a copy of the sco, act like it wasn't saved
231: // should throw an exception
232: if (curVal != null && _field == null)
233: throw new InternalException(_loc.get("no-savepoint-copy",
234: fmd));
235: }
236:
237: private void writeObject(ObjectOutputStream oos) throws IOException {
238: oos.defaultWriteObject();
239: _sm.writePC(oos, _copy);
240: }
241:
242: private void readObject(ObjectInputStream ois) throws IOException,
243: ClassNotFoundException {
244: ois.defaultReadObject();
245: _copy = _sm.readPC(ois);
246: }
247: }
|