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:
023: import org.apache.openjpa.jdbc.kernel.JDBCStore;
024: import org.apache.openjpa.jdbc.schema.Column;
025: import org.apache.openjpa.jdbc.schema.ColumnIO;
026: import org.apache.openjpa.jdbc.schema.Index;
027: import org.apache.openjpa.jdbc.schema.Schemas;
028: import org.apache.openjpa.jdbc.sql.Joins;
029: import org.apache.openjpa.jdbc.sql.Result;
030: import org.apache.openjpa.jdbc.sql.RowManager;
031: import org.apache.openjpa.jdbc.sql.SQLBuffer;
032: import org.apache.openjpa.jdbc.sql.Select;
033: import org.apache.openjpa.kernel.OpenJPAStateManager;
034: import org.apache.openjpa.lib.log.Log;
035: import org.apache.openjpa.lib.util.Localizer;
036: import org.apache.openjpa.meta.JavaTypes;
037: import org.apache.openjpa.meta.MetaDataContext;
038: import org.apache.openjpa.meta.MetaDataModes;
039: import org.apache.openjpa.meta.MetaDataRepository;
040: import org.apache.openjpa.util.InternalException;
041:
042: /**
043: * Handles determining the object class of database records.
044: *
045: * @author Abe White
046: */
047: public class Discriminator implements DiscriminatorStrategy,
048: MetaDataContext, MetaDataModes {
049:
050: /**
051: * Null discriminator value marker.
052: */
053: public static final Object NULL = new Object();
054:
055: private static final Localizer _loc = Localizer
056: .forPackage(Discriminator.class);
057:
058: private final ClassMapping _mapping;
059: private final DiscriminatorMappingInfo _info;
060: private DiscriminatorStrategy _strategy = null;
061: private int _resMode = MODE_NONE;
062:
063: private Column[] _cols = Schemas.EMPTY_COLUMNS;
064: private ColumnIO _io = null;
065: private Index _idx = null;
066: private boolean _subsLoaded = false;
067: private Object _value = null;
068:
069: private int _javaType = -1;
070:
071: /**
072: * Constructor. Supply owning mapping.
073: */
074: public Discriminator(ClassMapping mapping) {
075: _mapping = mapping;
076: _info = getMappingRepository().newMappingInfo(this );
077: }
078:
079: public MetaDataRepository getRepository() {
080: return _mapping.getRepository();
081: }
082:
083: public MappingRepository getMappingRepository() {
084: return _mapping.getMappingRepository();
085: }
086:
087: /**
088: * Return the owning mapping.
089: */
090: public ClassMapping getClassMapping() {
091: return _mapping;
092: }
093:
094: /**
095: * The strategy used for class discrimination.
096: */
097: public DiscriminatorStrategy getStrategy() {
098: return _strategy;
099: }
100:
101: /**
102: * The strategy used for class discrimination. The <code>adapt</code>
103: * parameter determines whether to adapt when mapping the strategy;
104: * use null if the strategy should not be mapped.
105: */
106: public void setStrategy(DiscriminatorStrategy strategy,
107: Boolean adapt) {
108: // set strategy first so we can access it during mapping
109: DiscriminatorStrategy orig = _strategy;
110: _strategy = strategy;
111: if (strategy != null) {
112: try {
113: strategy.setDiscriminator(this );
114: if (adapt != null)
115: strategy.map(adapt.booleanValue());
116: } catch (RuntimeException re) {
117: // reset strategy
118: _strategy = orig;
119: throw re;
120: }
121: }
122: }
123:
124: /**
125: * The discriminator value.
126: */
127: public Object getValue() {
128: return _value;
129: }
130:
131: /**
132: * The discriminator value.
133: */
134: public void setValue(Object value) {
135: _value = value;
136: }
137:
138: /**
139: * Raw mapping data.
140: */
141: public DiscriminatorMappingInfo getMappingInfo() {
142: return _info;
143: }
144:
145: /**
146: * Columns used by this Discriminator.
147: */
148: public Column[] getColumns() {
149: return _cols;
150: }
151:
152: /**
153: * Columns used by this Discriminator.
154: */
155: public void setColumns(Column[] cols) {
156: if (cols == null)
157: cols = Schemas.EMPTY_COLUMNS;
158: _cols = cols;
159: }
160:
161: /**
162: * I/O information on the discriminator columns.
163: */
164: public ColumnIO getColumnIO() {
165: return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
166: }
167:
168: /**
169: * I/O information on the discriminator columns.
170: */
171: public void setColumnIO(ColumnIO io) {
172: _io = io;
173: }
174:
175: /**
176: * Index on the Discriminator columns, or null if none.
177: */
178: public Index getIndex() {
179: return _idx;
180: }
181:
182: /**
183: * Index on the Discriminator columns, or null if none.
184: */
185: public void setIndex(Index idx) {
186: _idx = idx;
187: }
188:
189: /**
190: * Increment the reference count of used schema components.
191: */
192: public void refSchemaComponents() {
193: for (int i = 0; i < _cols.length; i++)
194: _cols[i].ref();
195: }
196:
197: /**
198: * Clear mapping information, including strategy.
199: */
200: public void clearMapping() {
201: _strategy = null;
202: _cols = Schemas.EMPTY_COLUMNS;
203: _idx = null;
204: _value = null;
205: _info.clear();
206: setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
207: }
208:
209: /**
210: * Update {@link MappingInfo} with our current mapping information.
211: */
212: public void syncMappingInfo() {
213: _info.syncWith(this );
214: }
215:
216: /**
217: * Resolve mode.
218: */
219: public int getResolve() {
220: return _resMode;
221: }
222:
223: /**
224: * Resolve mode.
225: */
226: public void setResolve(int mode) {
227: _resMode = mode;
228: }
229:
230: /**
231: * Resolve mode.
232: */
233: public void setResolve(int mode, boolean on) {
234: if (mode == MODE_NONE)
235: _resMode = mode;
236: else if (on)
237: _resMode |= mode;
238: else
239: _resMode &= ~mode;
240: }
241:
242: /**
243: * Resolve mapping information.
244: */
245: public boolean resolve(int mode) {
246: if ((_resMode & mode) == mode)
247: return true;
248: int cur = _resMode;
249: _resMode |= mode;
250: if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
251: resolveMapping();
252: if ((mode & MODE_MAPPING_INIT) != 0
253: && (cur & MODE_MAPPING_INIT) == 0)
254: _strategy.initialize();
255: return false;
256: }
257:
258: /**
259: * Setup mapping.
260: */
261: private void resolveMapping() {
262: // map strategy
263: MappingRepository repos = getMappingRepository();
264: if (_strategy == null)
265: repos.getStrategyInstaller().installStrategy(this );
266: Log log = repos.getLog();
267: if (log.isTraceEnabled())
268: log.trace(_loc.get("strategy", this , _strategy.getAlias()));
269:
270: // mark columns as mapped
271: Column[] cols = getColumns();
272: ColumnIO io = getColumnIO();
273: for (int i = 0; i < cols.length; i++) {
274: if (io.isInsertable(i, false))
275: cols[i].setFlag(Column.FLAG_DIRECT_INSERT, true);
276: if (io.isUpdatable(i, false))
277: cols[i].setFlag(Column.FLAG_DIRECT_UPDATE, true);
278: }
279: }
280:
281: /**
282: * Whether this Discriminator has loaded subclasses yet.
283: */
284: public boolean getSubclassesLoaded() {
285: if (!_subsLoaded) {
286: ClassMapping sup = _mapping.getPCSuperclassMapping();
287: if (sup != null
288: && sup.getDiscriminator().getSubclassesLoaded())
289: _subsLoaded = true;
290: }
291: return _subsLoaded;
292: }
293:
294: /**
295: * Whether this Discriminator has loaded subclasses yet.
296: */
297: public void setSubclassesLoaded(boolean loaded) {
298: _subsLoaded = loaded;
299: }
300:
301: /**
302: * Add WHERE conditions to the given select limiting the returned results
303: * to our mapping type, possibly including subclasses.
304: */
305: public boolean addClassConditions(Select sel, boolean subs,
306: Joins joins) {
307: if (_mapping.getJoinablePCSuperclassMapping() == null
308: && _mapping.getJoinablePCSubclassMappings().length == 0)
309: return false;
310: if (!hasClassConditions(_mapping, subs))
311: return false;
312:
313: // join down to base class where conditions will be added
314: ClassMapping from = _mapping;
315: ClassMapping sup = _mapping.getJoinablePCSuperclassMapping();
316: for (; sup != null; from = sup, sup = from
317: .getJoinablePCSuperclassMapping()) {
318: if (from.getTable() != sup.getTable()) {
319: if (joins == null)
320: joins = sel.newJoins();
321: joins = from.joinSuperclass(joins, false);
322: }
323: }
324:
325: sel
326: .where(getClassConditions(sel, joins, _mapping, subs),
327: joins);
328: return true;
329: }
330:
331: ////////////////////////////////////////
332: // DiscriminatorStrategy implementation
333: ////////////////////////////////////////
334:
335: public String getAlias() {
336: return assertStrategy().getAlias();
337: }
338:
339: public void map(boolean adapt) {
340: assertStrategy().map(adapt);
341: }
342:
343: public void initialize() {
344: assertStrategy().initialize();
345: }
346:
347: public void insert(OpenJPAStateManager sm, JDBCStore store,
348: RowManager rm) throws SQLException {
349: assertStrategy().insert(sm, store, rm);
350: }
351:
352: public void update(OpenJPAStateManager sm, JDBCStore store,
353: RowManager rm) throws SQLException {
354: assertStrategy().update(sm, store, rm);
355: }
356:
357: public void delete(OpenJPAStateManager sm, JDBCStore store,
358: RowManager rm) throws SQLException {
359: assertStrategy().delete(sm, store, rm);
360: }
361:
362: public Boolean isCustomInsert(OpenJPAStateManager sm,
363: JDBCStore store) {
364: return assertStrategy().isCustomInsert(sm, store);
365: }
366:
367: public Boolean isCustomUpdate(OpenJPAStateManager sm,
368: JDBCStore store) {
369: return assertStrategy().isCustomUpdate(sm, store);
370: }
371:
372: public Boolean isCustomDelete(OpenJPAStateManager sm,
373: JDBCStore store) {
374: return assertStrategy().isCustomDelete(sm, store);
375: }
376:
377: public void customInsert(OpenJPAStateManager sm, JDBCStore store)
378: throws SQLException {
379: assertStrategy().customInsert(sm, store);
380: }
381:
382: public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
383: throws SQLException {
384: assertStrategy().customUpdate(sm, store);
385: }
386:
387: public void customDelete(OpenJPAStateManager sm, JDBCStore store)
388: throws SQLException {
389: assertStrategy().customDelete(sm, store);
390: }
391:
392: public void setDiscriminator(Discriminator owner) {
393: assertStrategy().setDiscriminator(owner);
394: }
395:
396: public boolean select(Select sel, ClassMapping mapping) {
397: return assertStrategy().select(sel, mapping);
398: }
399:
400: public void loadSubclasses(JDBCStore store) throws SQLException,
401: ClassNotFoundException {
402: assertStrategy().loadSubclasses(store);
403: }
404:
405: public Class getClass(JDBCStore store, ClassMapping base,
406: Result result) throws SQLException, ClassNotFoundException {
407: return assertStrategy().getClass(store, base, result);
408: }
409:
410: public boolean hasClassConditions(ClassMapping base, boolean subs) {
411: return assertStrategy().hasClassConditions(base, subs);
412: }
413:
414: public SQLBuffer getClassConditions(Select sel, Joins joins,
415: ClassMapping base, boolean subs) {
416: return assertStrategy().getClassConditions(sel, joins, base,
417: subs);
418: }
419:
420: private DiscriminatorStrategy assertStrategy() {
421: if (_strategy == null)
422: throw new InternalException();
423: return _strategy;
424: }
425:
426: public String toString() {
427: return _mapping + "<discriminator>";
428: }
429:
430: public void setJavaType(int javaType) {
431: _javaType = javaType;
432: }
433:
434: public int getJavaType() {
435: if (_javaType == -1) {
436: ClassMapping superMapping = _mapping
437: .getPCSuperclassMapping();
438:
439: if (superMapping != null
440: && superMapping.getDiscriminator() != null) {
441: _javaType = superMapping.getDiscriminator()
442: .getJavaType();
443: }
444: }
445:
446: return _javaType;
447: }
448: }
|