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.jdbc.meta;
020:
021: import java.sql.SQLException;
022: import java.util.Map;
023:
024: import org.apache.openjpa.jdbc.kernel.JDBCStore;
025: import org.apache.openjpa.jdbc.schema.Column;
026: import org.apache.openjpa.jdbc.schema.ColumnIO;
027: import org.apache.openjpa.jdbc.schema.Index;
028: import org.apache.openjpa.jdbc.schema.Schemas;
029: import org.apache.openjpa.jdbc.sql.Result;
030: import org.apache.openjpa.jdbc.sql.RowManager;
031: import org.apache.openjpa.jdbc.sql.Select;
032: import org.apache.openjpa.kernel.OpenJPAStateManager;
033: import org.apache.openjpa.lib.log.Log;
034: import org.apache.openjpa.lib.util.Localizer;
035: import org.apache.openjpa.meta.MetaDataContext;
036: import org.apache.openjpa.meta.MetaDataModes;
037: import org.apache.openjpa.meta.MetaDataRepository;
038: import org.apache.openjpa.util.InternalException;
039:
040: /**
041: * Handles optimistic lock versioning for a class.
042: *
043: * @author Abe White
044: */
045: public class Version implements VersionStrategy, MetaDataContext,
046: MetaDataModes {
047:
048: private static final Localizer _loc = Localizer
049: .forPackage(Version.class);
050:
051: private final ClassMapping _mapping;
052: private final VersionMappingInfo _info;
053: private VersionStrategy _strategy = null;
054: private int _resMode = MODE_NONE;
055:
056: private Column[] _cols = Schemas.EMPTY_COLUMNS;
057: private ColumnIO _io = null;
058: private Index _idx = null;
059:
060: /**
061: * Constructor. Supply owning mapping.
062: */
063: public Version(ClassMapping mapping) {
064: _mapping = mapping;
065: _info = getMappingRepository().newMappingInfo(this );
066: }
067:
068: public MetaDataRepository getRepository() {
069: return _mapping.getRepository();
070: }
071:
072: public MappingRepository getMappingRepository() {
073: return _mapping.getMappingRepository();
074: }
075:
076: /**
077: * Return the owning mapping.
078: */
079: public ClassMapping getClassMapping() {
080: return _mapping;
081: }
082:
083: /**
084: * The strategy used for versioning.
085: */
086: public VersionStrategy getStrategy() {
087: return _strategy;
088: }
089:
090: /**
091: * The strategy used for versioning. The <code>adapt</code>
092: * parameter determines whether to adapt when mapping the strategy;
093: * use null if the strategy should not be mapped.
094: */
095: public void setStrategy(VersionStrategy strategy, Boolean adapt) {
096: // set strategy first so we can access it during mapping
097: VersionStrategy orig = _strategy;
098: _strategy = strategy;
099: if (strategy != null) {
100: try {
101: strategy.setVersion(this );
102: if (adapt != null)
103: strategy.map(adapt.booleanValue());
104: } catch (RuntimeException re) {
105: // reset strategy
106: _strategy = orig;
107: throw re;
108: }
109: }
110: }
111:
112: /**
113: * Raw mapping data.
114: */
115: public VersionMappingInfo getMappingInfo() {
116: return _info;
117: }
118:
119: /**
120: * Columns used for versioning.
121: */
122: public Column[] getColumns() {
123: return _cols;
124: }
125:
126: /**
127: * Columns used for versioning.
128: */
129: public void setColumns(Column[] cols) {
130: if (cols == null)
131: cols = Schemas.EMPTY_COLUMNS;
132: _cols = cols;
133: }
134:
135: /**
136: * I/O information on the version columns.
137: */
138: public ColumnIO getColumnIO() {
139: return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
140: }
141:
142: /**
143: * I/O information on the version columns.
144: */
145: public void setColumnIO(ColumnIO io) {
146: _io = io;
147: }
148:
149: /**
150: * Index on the version columns, or null if none.
151: */
152: public Index getIndex() {
153: return _idx;
154: }
155:
156: /**
157: * Index on the version columns, or null if none.
158: */
159: public void setIndex(Index idx) {
160: _idx = idx;
161: }
162:
163: /**
164: * Increment the reference count of used schema components.
165: */
166: public void refSchemaComponents() {
167: for (int i = 0; i < _cols.length; i++)
168: _cols[i].ref();
169: }
170:
171: /**
172: * Clear mapping information, including strategy.
173: */
174: public void clearMapping() {
175: _strategy = null;
176: _cols = Schemas.EMPTY_COLUMNS;
177: _idx = null;
178: _info.clear();
179: setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
180: }
181:
182: /**
183: * Update {@link MappingInfo} with our current mapping information.
184: */
185: public void syncMappingInfo() {
186: _info.syncWith(this );
187:
188: // setup the version field with our mapping info
189: FieldMapping fm = _mapping.getVersionFieldMapping();
190: if (fm != null) {
191: // erase explicit strategy if it is standard version strategy for
192: // field type
193: if (_info.getStrategy() != null
194: && _info.getStrategy().equals(
195: getMappingRepository().defaultStrategy(
196: this , fm).getAlias()))
197: _info.setStrategy(null);
198:
199: fm.getMappingInfo().clear();
200: fm.getValueInfo().clear();
201: fm.getKeyMapping().getValueInfo().clear();
202: fm.getElementMapping().getValueInfo().clear();
203: fm.getValueInfo().copy(_info);
204: _info.clear();
205: }
206: }
207:
208: /**
209: * Resolve mode.
210: */
211: public int getResolve() {
212: return _resMode;
213: }
214:
215: /**
216: * Resolve mode.
217: */
218: public void setResolve(int mode) {
219: _resMode = mode;
220: }
221:
222: /**
223: * Resolve mode.
224: */
225: public void setResolve(int mode, boolean on) {
226: if (mode == MODE_NONE)
227: _resMode = mode;
228: else if (on)
229: _resMode |= mode;
230: else
231: _resMode &= ~mode;
232: }
233:
234: /**
235: * Resolve mapping information.
236: */
237: public boolean resolve(int mode) {
238: if ((_resMode & mode) == mode)
239: return true;
240: int cur = _resMode;
241: _resMode |= mode;
242: if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
243: resolveMapping();
244: if ((mode & MODE_MAPPING_INIT) != 0
245: && (cur & MODE_MAPPING_INIT) == 0)
246: _strategy.initialize();
247: return false;
248: }
249:
250: /**
251: * Setup mapping.
252: */
253: private void resolveMapping() {
254: // if there is a version field, copy mapping info from it
255: FieldMapping fm = _mapping.getVersionFieldMapping();
256: if (fm != null)
257: _info.copy(fm.getValueInfo());
258:
259: // map strategy
260: MappingRepository repos = getMappingRepository();
261: if (_strategy == null)
262: repos.getStrategyInstaller().installStrategy(this );
263: Log log = repos.getLog();
264: if (log.isTraceEnabled())
265: log.trace(_loc.get("strategy", this , _strategy.getAlias()));
266:
267: // mark columns as mapped
268: Column[] cols = getColumns();
269: ColumnIO io = getColumnIO();
270: for (int i = 0; i < cols.length; i++) {
271: if (io.isInsertable(i, false))
272: cols[i].setFlag(Column.FLAG_DIRECT_INSERT, true);
273: if (io.isUpdatable(i, false))
274: cols[i].setFlag(Column.FLAG_DIRECT_UPDATE, true);
275: }
276: }
277:
278: //////////////////////////////////
279: // VersionStrategy implementation
280: //////////////////////////////////
281:
282: public String getAlias() {
283: return assertStrategy().getAlias();
284: }
285:
286: public void map(boolean adapt) {
287: assertStrategy().map(adapt);
288: }
289:
290: public void initialize() {
291: assertStrategy().initialize();
292: }
293:
294: public void insert(OpenJPAStateManager sm, JDBCStore store,
295: RowManager rm) throws SQLException {
296: assertStrategy().insert(sm, store, rm);
297: }
298:
299: public void update(OpenJPAStateManager sm, JDBCStore store,
300: RowManager rm) throws SQLException {
301: assertStrategy().update(sm, store, rm);
302: }
303:
304: public void delete(OpenJPAStateManager sm, JDBCStore store,
305: RowManager rm) throws SQLException {
306: assertStrategy().delete(sm, store, rm);
307: }
308:
309: public Boolean isCustomInsert(OpenJPAStateManager sm,
310: JDBCStore store) {
311: return assertStrategy().isCustomInsert(sm, store);
312: }
313:
314: public Boolean isCustomUpdate(OpenJPAStateManager sm,
315: JDBCStore store) {
316: return assertStrategy().isCustomUpdate(sm, store);
317: }
318:
319: public Boolean isCustomDelete(OpenJPAStateManager sm,
320: JDBCStore store) {
321: return assertStrategy().isCustomDelete(sm, store);
322: }
323:
324: public void customInsert(OpenJPAStateManager sm, JDBCStore store)
325: throws SQLException {
326: assertStrategy().customInsert(sm, store);
327: }
328:
329: public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
330: throws SQLException {
331: assertStrategy().customUpdate(sm, store);
332: }
333:
334: public void customDelete(OpenJPAStateManager sm, JDBCStore store)
335: throws SQLException {
336: assertStrategy().customDelete(sm, store);
337: }
338:
339: public void setVersion(Version owner) {
340: assertStrategy().setVersion(owner);
341: }
342:
343: public boolean select(Select sel, ClassMapping mapping) {
344: return assertStrategy().select(sel, mapping);
345: }
346:
347: public void load(OpenJPAStateManager sm, JDBCStore store, Result res)
348: throws SQLException {
349: assertStrategy().load(sm, store, res);
350: }
351:
352: public void afterLoad(OpenJPAStateManager sm, JDBCStore store) {
353: assertStrategy().afterLoad(sm, store);
354: }
355:
356: public boolean checkVersion(OpenJPAStateManager sm,
357: JDBCStore store, boolean updateVersion) throws SQLException {
358: return assertStrategy().checkVersion(sm, store, updateVersion);
359: }
360:
361: public int compareVersion(Object v1, Object v2) {
362: return assertStrategy().compareVersion(v1, v2);
363: }
364:
365: private VersionStrategy assertStrategy() {
366: if (_strategy == null)
367: throw new InternalException();
368: return _strategy;
369: }
370:
371: public String toString() {
372: return _mapping + "<version>";
373: }
374:
375: /**
376: * @return a Map<Column,String> specifying how to update each version
377: * column in this instance during a bulk update.
378: *
379: * @since 1.0.0
380: */
381: public Map getBulkUpdateValues() {
382: return _strategy.getBulkUpdateValues();
383: }
384: }
|