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.strats;
020:
021: import java.sql.SQLException;
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Collections;
025: import java.util.Iterator;
026: import java.util.Map;
027: import java.util.NoSuchElementException;
028:
029: import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
030: import org.apache.openjpa.jdbc.kernel.JDBCStore;
031: import org.apache.openjpa.jdbc.meta.ClassMapping;
032: import org.apache.openjpa.jdbc.schema.Column;
033: import org.apache.openjpa.jdbc.sql.Joins;
034: import org.apache.openjpa.jdbc.sql.Result;
035: import org.apache.openjpa.jdbc.sql.SQLBuffer;
036: import org.apache.openjpa.jdbc.sql.SQLExceptions;
037: import org.apache.openjpa.jdbc.sql.Select;
038: import org.apache.openjpa.jdbc.sql.Union;
039: import org.apache.openjpa.kernel.OpenJPAStateManager;
040: import org.apache.openjpa.lib.util.Closeable;
041: import org.apache.openjpa.lib.util.Localizer;
042: import org.apache.openjpa.util.AbstractLRSProxyMap;
043: import org.apache.openjpa.util.InvalidStateException;
044:
045: /**
046: * Large result set map.
047: *
048: * @author Abe White
049: */
050: class LRSProxyMap extends AbstractLRSProxyMap {
051:
052: private static final Localizer _loc = Localizer
053: .forPackage(LRSProxyMap.class);
054:
055: private final LRSMapFieldStrategy _strat;
056:
057: public LRSProxyMap(LRSMapFieldStrategy strat) {
058: super (strat.getFieldMapping().getKey().getDeclaredType(), strat
059: .getFieldMapping().getElement().getDeclaredType());
060: _strat = strat;
061: }
062:
063: protected synchronized int count() {
064: boolean derivedVal = _strat.getFieldMapping().getElement()
065: .getValueMappedBy() != null;
066: final ClassMapping[] clss = (derivedVal) ? _strat
067: .getIndependentKeyMappings(false) : _strat
068: .getIndependentValueMappings(false);
069: final OpenJPAStateManager sm = assertOwner();
070: final JDBCStore store = getStore();
071: Union union = store.getSQLFactory().newUnion(
072: Math.max(1, clss.length));
073: union.select(new Union.Selector() {
074: public void select(Select sel, int idx) {
075: ClassMapping cls = (clss.length == 0) ? null
076: : clss[idx];
077: sel.whereForeignKey(_strat.getJoinForeignKey(cls), sm
078: .getObjectId(), _strat.getFieldMapping()
079: .getDefiningMapping(), store);
080: }
081: });
082:
083: try {
084: return union.getCount(store);
085: } catch (SQLException se) {
086: throw SQLExceptions.getStore(se, store.getDBDictionary());
087: }
088: }
089:
090: protected boolean hasKey(Object key) {
091: return has(key, true);
092: }
093:
094: protected boolean hasValue(Object value) {
095: return has(value, false);
096: }
097:
098: private boolean has(final Object obj, final boolean key) {
099: final boolean derivedKey = key
100: && _strat.getFieldMapping().getKey().getValueMappedBy() != null;
101: final boolean derivedVal = !key
102: && _strat.getFieldMapping().getElement()
103: .getValueMappedBy() != null;
104:
105: final ClassMapping[] clss = ((key && !derivedKey) || derivedVal) ? _strat
106: .getIndependentKeyMappings(derivedVal)
107: : _strat.getIndependentValueMappings(derivedKey);
108: final OpenJPAStateManager sm = assertOwner();
109: final JDBCStore store = getStore();
110:
111: Union union = store.getSQLFactory().newUnion(
112: Math.max(1, clss.length));
113: union.select(new Union.Selector() {
114: public void select(Select sel, int idx) {
115: ClassMapping cls = (clss.length == 0) ? null
116: : clss[idx];
117: sel.whereForeignKey(_strat.getJoinForeignKey(cls), sm
118: .getObjectId(), _strat.getFieldMapping()
119: .getDefiningMapping(), store);
120:
121: Joins joins = null;
122: Column[] cols;
123: Object val;
124: if (key) {
125: if (derivedKey)
126: joins = _strat.joinValueRelation(
127: sel.newJoins(), cls);
128: val = _strat.toKeyDataStoreValue(obj, store);
129: cols = _strat.getKeyColumns(cls);
130: } else {
131: if (derivedVal)
132: joins = _strat.joinKeyRelation(sel.newJoins(),
133: cls);
134: val = _strat.toDataStoreValue(obj, store);
135: cols = _strat.getValueColumns(cls);
136: }
137: Object[] vals = (cols.length == 1) ? null
138: : (Object[]) val;
139: SQLBuffer sql = new SQLBuffer(store.getDBDictionary());
140: for (int i = 0; i < cols.length; i++) {
141: if (i > 0)
142: sql.append(" AND ");
143:
144: sql.append(sel.getColumnAlias(cols[i], joins));
145: if (vals == null)
146: sql.append((val == null) ? " IS " : " = ")
147: .appendValue(val, cols[i]);
148: else
149: sql.append((vals[i] == null) ? " IS " : " = ")
150: .appendValue(vals[i], cols[i]);
151: }
152: sel.where(sql, joins);
153: }
154: });
155:
156: try {
157: return union.getCount(store) > 0;
158: } catch (SQLException se) {
159: throw SQLExceptions.getStore(se, store.getDBDictionary());
160: }
161: }
162:
163: protected Collection keys(final Object obj) {
164: final OpenJPAStateManager sm = assertOwner();
165: final JDBCStore store = getStore();
166: if (_strat.getFieldMapping().getKey().getValueMappedBy() != null) {
167: Object key = _strat.deriveKey(store, obj);
168: if (hasKey(key))
169: return Collections.singleton(key);
170: return Collections.EMPTY_LIST;
171: }
172:
173: final ClassMapping[] clss = _strat
174: .getIndependentKeyMappings(true);
175: final JDBCFetchConfiguration fetch = store
176: .getFetchConfiguration();
177: final Joins[] resJoins = new Joins[Math.max(1, clss.length)];
178:
179: Union union = store.getSQLFactory().newUnion(
180: Math.max(1, clss.length));
181: if (fetch.getSubclassFetchMode(_strat.getFieldMapping()
182: .getKeyMapping().getTypeMapping()) != fetch.EAGER_JOIN)
183: union.abortUnion();
184: union.select(new Union.Selector() {
185: public void select(Select sel, int idx) {
186: ClassMapping cls = (clss.length == 0) ? null
187: : clss[idx];
188: sel.whereForeignKey(_strat.getJoinForeignKey(cls), sm
189: .getObjectId(), _strat.getFieldMapping()
190: .getDefiningMapping(), store);
191: if (_strat.getFieldMapping().getElement()
192: .getValueMappedBy() != null)
193: resJoins[idx] = _strat.joinKeyRelation(sel
194: .newJoins(), cls);
195:
196: Object val = _strat.toDataStoreValue(obj, store);
197: Column[] cols = _strat.getValueColumns(cls);
198: Object[] vals = (cols.length == 1) ? null
199: : (Object[]) val;
200: SQLBuffer sql = new SQLBuffer(store.getDBDictionary());
201: for (int i = 0; i < cols.length; i++) {
202: if (i > 0)
203: sql.append(" AND ");
204:
205: sql.append(sel.getColumnAlias(cols[i]));
206: if (vals == null)
207: sql.append((val == null) ? " IS " : " = ")
208: .appendValue(val, cols[i]);
209: else
210: sql.append((vals[i] == null) ? " IS " : " = ")
211: .appendValue(vals[i], cols[i]);
212: }
213: sel.where(sql);
214:
215: if (resJoins[idx] == null)
216: resJoins[idx] = _strat.joinKeyRelation(sel
217: .newJoins(), cls);
218: _strat.selectKey(sel, cls, sm, store, fetch,
219: resJoins[idx]);
220: }
221: });
222:
223: Result res = null;
224: Collection keys = new ArrayList(3);
225: try {
226: res = union.execute(store, fetch);
227: while (res.next())
228: keys.add(_strat.loadKey(sm, store, fetch, res,
229: resJoins[res.indexOf()]));
230: return keys;
231: } catch (SQLException se) {
232: throw SQLExceptions.getStore(se, store.getDBDictionary());
233: } finally {
234: if (res != null)
235: res.close();
236: }
237: }
238:
239: protected Object value(final Object obj) {
240: final OpenJPAStateManager sm = assertOwner();
241: final JDBCStore store = getStore();
242: if (_strat.getFieldMapping().getElement().getValueMappedBy() != null) {
243: Object val = _strat.deriveValue(store, obj);
244: if (hasValue(val))
245: return val;
246: return null;
247: }
248:
249: final JDBCFetchConfiguration fetch = store
250: .getFetchConfiguration();
251: final ClassMapping[] clss = _strat
252: .getIndependentValueMappings(true);
253: final Joins[] resJoins = new Joins[Math.max(1, clss.length)];
254: Union union = store.getSQLFactory().newUnion(
255: Math.max(1, clss.length));
256: union.setExpectedResultCount(1, false);
257: if (fetch.getSubclassFetchMode(_strat.getFieldMapping()
258: .getElementMapping().getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
259: union.abortUnion();
260: union.select(new Union.Selector() {
261: public void select(Select sel, int idx) {
262: ClassMapping cls = (clss.length == 0) ? null
263: : clss[idx];
264: sel.whereForeignKey(_strat.getJoinForeignKey(cls), sm
265: .getObjectId(), _strat.getFieldMapping()
266: .getDefiningMapping(), store);
267: if (_strat.getFieldMapping().getKey()
268: .getValueMappedBy() != null)
269: resJoins[idx] = _strat.joinValueRelation(sel
270: .newJoins(), cls);
271:
272: Object key = _strat.toKeyDataStoreValue(obj, store);
273: Column[] cols = _strat.getKeyColumns(cls);
274: Object[] vals = (cols.length == 1) ? null
275: : (Object[]) key;
276: SQLBuffer sql = new SQLBuffer(store.getDBDictionary());
277: for (int i = 0; i < cols.length; i++) {
278: if (i > 0)
279: sql.append(" AND ");
280:
281: sql.append(sel.getColumnAlias(cols[i],
282: resJoins[idx]));
283: if (vals == null)
284: sql.append((key == null) ? " IS " : " = ")
285: .appendValue(key, cols[i]);
286: else
287: sql.append((vals[i] == null) ? " IS " : " = ")
288: .appendValue(vals[i], cols[i]);
289: }
290: sel.where(sql, resJoins[idx]);
291:
292: if (resJoins[idx] == null)
293: resJoins[idx] = _strat.joinValueRelation(sel
294: .newJoins(), cls);
295: _strat.selectValue(sel, cls, sm, store, fetch,
296: resJoins[idx]);
297: }
298: });
299:
300: Result res = null;
301: try {
302: res = union.execute(store, fetch);
303: if (res.next())
304: return _strat.loadValue(sm, store, fetch, res,
305: resJoins[res.indexOf()]);
306: return null;
307: } catch (SQLException se) {
308: throw SQLExceptions.getStore(se, store.getDBDictionary());
309: } finally {
310: if (res != null)
311: res.close();
312: }
313: }
314:
315: protected Iterator itr() {
316: OpenJPAStateManager sm = assertOwner();
317: JDBCStore store = getStore();
318: JDBCFetchConfiguration fetch = store.getFetchConfiguration();
319: try {
320: Joins[] joins = new Joins[2];
321: Result[] res = _strat.getResults(sm, store, fetch,
322: fetch.EAGER_JOIN, joins, true);
323: return new ResultIterator(sm, store, fetch, res, joins);
324: } catch (SQLException se) {
325: throw SQLExceptions.getStore(se, store.getDBDictionary());
326: }
327: }
328:
329: private OpenJPAStateManager assertOwner() {
330: OpenJPAStateManager sm = getOwner();
331: if (sm == null)
332: throw new InvalidStateException(_loc.get("lrs-no-owner",
333: _strat.getFieldMapping()));
334: return sm;
335: }
336:
337: private JDBCStore getStore() {
338: return (JDBCStore) getOwner().getContext().getStoreManager()
339: .getInnermostDelegate();
340: }
341:
342: /**
343: * Closeable iterator built around key and value JDBC results.
344: */
345: private class ResultIterator implements Iterator, Closeable {
346:
347: private final OpenJPAStateManager _sm;
348: private final JDBCStore _store;
349: private final JDBCFetchConfiguration _fetch;
350: private final Result[] _res;
351: private final Joins[] _joins;
352: private Boolean _next = null;
353:
354: public ResultIterator(OpenJPAStateManager sm, JDBCStore store,
355: JDBCFetchConfiguration fetch, Result[] res,
356: Joins[] joins) {
357: _sm = sm;
358: _store = store;
359: _fetch = fetch;
360: _res = res;
361: _joins = joins;
362: }
363:
364: public boolean hasNext() {
365: if (_next == null) {
366: try {
367: _next = (_res[0].next()) ? Boolean.TRUE
368: : Boolean.FALSE;
369: if (_next.booleanValue() && _res[1] != _res[0])
370: _res[1].next();
371: } catch (SQLException se) {
372: throw SQLExceptions.getStore(se, _store
373: .getDBDictionary());
374: }
375: }
376: return _next.booleanValue();
377: }
378:
379: public Object next() {
380: if (!hasNext())
381: throw new NoSuchElementException();
382: _next = null;
383:
384: boolean keyDerived = _strat.getFieldMapping().getKey()
385: .getValueMappedBy() != null;
386: boolean valDerived = _strat.getFieldMapping().getElement()
387: .getValueMappedBy() != null;
388: Entry entry = new Entry();
389: try {
390:
391: if (!keyDerived)
392: entry.key = _strat.loadKey(_sm, _store, _fetch,
393: _res[0], _joins[0]);
394: if (!valDerived)
395: entry.val = _strat.loadValue(_sm, _store, _fetch,
396: _res[1], _joins[1]);
397: if (keyDerived)
398: entry.key = _strat.deriveKey(_store, entry.val);
399: if (valDerived)
400: entry.val = _strat.deriveValue(_store, entry.key);
401: return entry;
402: } catch (SQLException se) {
403: throw SQLExceptions.getStore(se, _store
404: .getDBDictionary());
405: }
406: }
407:
408: public void remove() {
409: throw new UnsupportedOperationException();
410: }
411:
412: public void close() {
413: _next = Boolean.FALSE;
414: _res[0].close();
415: if (_res[1] != _res[0])
416: _res[1].close();
417: }
418: }
419:
420: /**
421: * Map.Entry struct.
422: */
423: private static class Entry implements Map.Entry {
424:
425: public Object key;
426: public Object val;
427:
428: public Object getKey() {
429: return key;
430: }
431:
432: public Object getValue() {
433: return val;
434: }
435:
436: public Object setValue(Object val) {
437: throw new UnsupportedOperationException();
438: }
439: }
440: }
|