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.*;
022: import java.util.*;
023:
024: import org.apache.openjpa.lib.util.*;
025:
026: import org.apache.openjpa.kernel.*;
027: import org.apache.openjpa.util.*;
028: import org.apache.openjpa.meta.*;
029: import org.apache.openjpa.jdbc.meta.*;
030: import org.apache.openjpa.jdbc.kernel.*;
031: import org.apache.openjpa.jdbc.schema.*;
032: import org.apache.openjpa.jdbc.sql.*;
033:
034: /**
035: * <p>Mapping for a collection of values in a separate table controlled by a
036: * {@link ValueHandler}.</p>
037: *
038: * @author Abe White
039: * @since 0.4.0, 1.1.0
040: */
041: public class HandlerCollectionTableFieldStrategy extends
042: StoreCollectionFieldStrategy implements
043: LRSCollectionFieldStrategy {
044:
045: private static final Localizer _loc = Localizer
046: .forPackage(HandlerCollectionTableFieldStrategy.class);
047:
048: private Column[] _cols = null;
049: private ColumnIO _io = null;
050: private boolean _load = false;
051: private boolean _lob = false;
052: private boolean _embed = false;
053:
054: public FieldMapping getFieldMapping() {
055: return field;
056: }
057:
058: public ClassMapping[] getIndependentElementMappings(boolean traverse) {
059: return ClassMapping.EMPTY_MAPPINGS;
060: }
061:
062: public Column[] getElementColumns(ClassMapping elem) {
063: return _cols;
064: }
065:
066: public ForeignKey getJoinForeignKey(ClassMapping elem) {
067: return field.getJoinForeignKey();
068: }
069:
070: public void selectElement(Select sel, ClassMapping elem,
071: JDBCStore store, JDBCFetchConfiguration fetch,
072: int eagerMode, Joins joins) {
073: sel.select(_cols, joins);
074: }
075:
076: public Object loadElement(OpenJPAStateManager sm, JDBCStore store,
077: JDBCFetchConfiguration fetch, Result res, Joins joins)
078: throws SQLException {
079: return HandlerStrategies.loadObject(field.getElementMapping(),
080: sm, store, fetch, res, joins, _cols, _load);
081: }
082:
083: protected Joins join(Joins joins, ClassMapping elem) {
084: return join(joins, false);
085: }
086:
087: public Joins joinElementRelation(Joins joins, ClassMapping elem) {
088: return joinRelation(joins, false, false);
089: }
090:
091: protected Proxy newLRSProxy() {
092: return new LRSProxyCollection(this );
093: }
094:
095: public void map(boolean adapt) {
096: if (field.getTypeCode() != JavaTypes.COLLECTION
097: && field.getTypeCode() != JavaTypes.ARRAY)
098: throw new MetaDataException(_loc.get("not-coll", field));
099:
100: assertNotMappedBy();
101: field.getValueInfo().assertNoSchemaComponents(field, !adapt);
102: field.getKeyMapping().getValueInfo().assertNoSchemaComponents(
103: field.getKey(), !adapt);
104:
105: ValueMapping elem = field.getElementMapping();
106: if (elem.getHandler() == null)
107: throw new MetaDataException(_loc.get("no-handler", elem));
108:
109: field.mapJoin(adapt, true);
110: _io = new ColumnIO();
111: _cols = HandlerStrategies.map(elem, "element", _io, adapt);
112:
113: FieldMappingInfo finfo = field.getMappingInfo();
114: Column orderCol = finfo.getOrderColumn(field, field.getTable(),
115: adapt);
116: field.setOrderColumn(orderCol);
117: field.setOrderColumnIO(finfo.getColumnIO());
118: field.mapPrimaryKey(adapt);
119: }
120:
121: public void initialize() {
122: for (int i = 0; !_lob && i < _cols.length; i++)
123: _lob = _cols[i].isLob();
124:
125: ValueMapping elem = field.getElementMapping();
126: _embed = elem.getEmbeddedMetaData() != null;
127: _load = elem.getHandler().objectValueRequiresLoad(elem);
128: }
129:
130: public void insert(OpenJPAStateManager sm, JDBCStore store,
131: RowManager rm) throws SQLException {
132: insert(sm, store, rm, sm.fetchObject(field.getIndex()));
133: }
134:
135: private void insert(OpenJPAStateManager sm, JDBCStore store,
136: RowManager rm, Object vals) throws SQLException {
137: Collection coll;
138: if (field.getTypeCode() == JavaTypes.ARRAY)
139: coll = JavaTypes.toList(vals, field.getElement().getType(),
140: false);
141: else
142: coll = (Collection) vals;
143: if (coll == null || coll.isEmpty())
144: return;
145:
146: Row row = rm.getSecondaryRow(field.getTable(),
147: Row.ACTION_INSERT);
148: row.setForeignKey(field.getJoinForeignKey(), field
149: .getJoinColumnIO(), sm);
150:
151: ValueMapping elem = field.getElementMapping();
152: Column order = field.getOrderColumn();
153: boolean setOrder = field.getOrderColumnIO().isInsertable(order,
154: false);
155: int idx = 0;
156: for (Iterator itr = coll.iterator(); itr.hasNext(); idx++) {
157: HandlerStrategies.set(elem, itr.next(), store, row, _cols,
158: _io, true);
159: if (setOrder)
160: row.setInt(order, idx);
161: rm.flushSecondaryRow(row);
162: }
163: }
164:
165: public void update(OpenJPAStateManager sm, JDBCStore store,
166: RowManager rm) throws SQLException {
167: Object obj = sm.fetchObject(field.getIndex());
168: ChangeTracker ct = null;
169: if (obj instanceof Proxy) {
170: Proxy proxy = (Proxy) obj;
171: if (Proxies.isOwner(proxy, sm, field.getIndex()))
172: ct = proxy.getChangeTracker();
173: }
174:
175: // if no fine-grained change tracking then just delete and reinsert
176: if (ct == null || !ct.isTracking()) {
177: delete(sm, store, rm);
178: insert(sm, store, rm, obj);
179: return;
180: }
181:
182: // delete the removes
183: ValueMapping elem = field.getElementMapping();
184: Collection rem = ct.getRemoved();
185: if (!rem.isEmpty()) {
186: Row delRow = rm.getSecondaryRow(field.getTable(),
187: Row.ACTION_DELETE);
188: delRow.whereForeignKey(field.getJoinForeignKey(), sm);
189: for (Iterator itr = rem.iterator(); itr.hasNext();) {
190: HandlerStrategies.where(elem, itr.next(), store,
191: delRow, _cols);
192: rm.flushSecondaryRow(delRow);
193: }
194: }
195:
196: // insert the adds
197: Collection add = ct.getAdded();
198: if (!add.isEmpty()) {
199: Row addRow = rm.getSecondaryRow(field.getTable(),
200: Row.ACTION_INSERT);
201: addRow.setForeignKey(field.getJoinForeignKey(), field
202: .getJoinColumnIO(), sm);
203:
204: int seq = ct.getNextSequence();
205: Column order = field.getOrderColumn();
206: boolean setOrder = field.getOrderColumnIO().isInsertable(
207: order, false);
208: for (Iterator itr = add.iterator(); itr.hasNext(); seq++) {
209: HandlerStrategies.set(elem, itr.next(), store, addRow,
210: _cols, _io, true);
211: if (setOrder)
212: addRow.setInt(order, seq);
213: rm.flushSecondaryRow(addRow);
214: }
215: if (order != null)
216: ct.setNextSequence(seq);
217: }
218: }
219:
220: public void delete(OpenJPAStateManager sm, JDBCStore store,
221: RowManager rm) throws SQLException {
222: Row row = rm.getAllRows(field.getTable(), Row.ACTION_DELETE);
223: row.whereForeignKey(field.getJoinForeignKey(), sm);
224: rm.flushAllRows(row);
225: }
226:
227: public int supportsSelect(Select sel, int type,
228: OpenJPAStateManager sm, JDBCStore store,
229: JDBCFetchConfiguration fetch) {
230: // can't do any combined select with lobs, since they don't allow
231: // select distinct. cant select eager parallel on embedded, because
232: // during parallel result processing the owning sm won't be available
233: // for each elem
234: if (_lob || (_embed && type == Select.EAGER_PARALLEL))
235: return 0;
236: return super .supportsSelect(sel, type, sm, store, fetch);
237: }
238:
239: public Object toDataStoreValue(Object val, JDBCStore store) {
240: return HandlerStrategies.toDataStoreValue(field
241: .getElementMapping(), val, _cols, store);
242: }
243:
244: public Joins join(Joins joins, boolean forceOuter) {
245: return field.join(joins, forceOuter, true);
246: }
247:
248: public Joins joinRelation(Joins joins, boolean forceOuter,
249: boolean traverse) {
250: if (traverse)
251: HandlerStrategies.assertJoinable(field.getElementMapping());
252: return joins;
253: }
254: }
|