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: import org.apache.openjpa.kernel.*;
026: import org.apache.openjpa.util.*;
027: import org.apache.openjpa.jdbc.meta.*;
028: import org.apache.openjpa.jdbc.kernel.*;
029: import org.apache.openjpa.jdbc.schema.*;
030:
031: /**
032: * <p>Handler for embedded objects as elements of a collection or map. For
033: * embedded objects as fields, use the more powerful
034: * {@link EmbedFieldStrategy}.</p>
035: *
036: * @author Abe White
037: * @since 0.4.0, 1.1.0
038: * @nojavadoc
039: */
040: public class ElementEmbedValueHandler extends EmbedValueHandler
041: implements RelationId {
042:
043: private static final Localizer _loc = Localizer
044: .forPackage(ElementEmbedValueHandler.class);
045:
046: private ValueMapping _vm = null;
047: private Column[] _cols = null;
048: private Object[] _args = null;
049: private int _nullIdx = -1;
050: private boolean _synthetic = false;
051:
052: public Column[] map(ValueMapping vm, String name, ColumnIO io,
053: boolean adapt) {
054: LinkedList cols = new LinkedList();
055: LinkedList args = new LinkedList();
056: super .map(vm, name, io, adapt, cols, args);
057:
058: ValueMappingInfo vinfo = vm.getValueInfo();
059: Column nullInd = vinfo.getNullIndicatorColumn(vm, name, vm
060: .getFieldMapping().getTable(), adapt);
061: if (nullInd != null)
062: vm.setColumns(new Column[] { nullInd });
063:
064: // record index of null indicator column and whether it is synthetic
065: if (nullInd != null) {
066: _nullIdx = cols.indexOf(nullInd);
067: if (_nullIdx == -1) {
068: cols.addFirst(nullInd);
069: args.addFirst(null);
070: _nullIdx = 0;
071: _synthetic = true;
072: }
073: }
074:
075: _vm = vm;
076: _cols = (Column[]) cols.toArray(new Column[cols.size()]);
077: _args = args.toArray();
078: return _cols;
079: }
080:
081: public boolean objectValueRequiresLoad(ValueMapping vm) {
082: return true;
083: }
084:
085: public Object getResultArgument(ValueMapping vm) {
086: return _args;
087: }
088:
089: public Object toDataStoreValue(ValueMapping vm, Object val,
090: JDBCStore store) {
091: OpenJPAStateManager em = store.getContext()
092: .getStateManager(val);
093: Object rval = null;
094: if (_cols.length > 1)
095: rval = new Object[_cols.length];
096:
097: // set null indicator column
098: int idx = 0;
099: if (_synthetic) {
100: Object cval = ((EmbeddedClassStrategy) vm
101: .getEmbeddedMapping().getStrategy())
102: .getNullIndicatorValue(em);
103: if (_cols.length == 1)
104: return cval;
105: ((Object[]) rval)[idx++] = cval;
106: }
107:
108: return super .toDataStoreValue(em, vm, store, _cols, rval, idx);
109: }
110:
111: public Object toObjectValue(ValueMapping vm, Object val,
112: OpenJPAStateManager sm, JDBCStore store,
113: JDBCFetchConfiguration fetch) throws SQLException {
114: if (sm == null)
115: throw new InvalidStateException(_loc.get(
116: "cant-project-owned", vm));
117:
118: // check null indicator first
119: if (_nullIdx != -1) {
120: Object nval;
121: if (_cols.length == 1)
122: nval = val;
123: else
124: nval = ((Object[]) val)[_nullIdx];
125: if (((EmbeddedClassStrategy) vm.getEmbeddedMapping()
126: .getStrategy()).indicatesNull(nval))
127: return null;
128: }
129:
130: // create embedded instance
131: OpenJPAStateManager em = store.getContext().embed(null, null,
132: sm, vm);
133: int idx = (_synthetic) ? 1 : 0;
134: super .toObjectValue(em, vm, val, store, fetch, _cols, idx);
135:
136: // after loading everything from result, load the rest of the
137: // configured fields
138: em.load(fetch);
139: return em.getManagedInstance();
140: }
141:
142: /////////////////////////////
143: // RelationId implementation
144: /////////////////////////////
145:
146: public Object toRelationDataStoreValue(OpenJPAStateManager sm,
147: Column col) {
148: return toRelationDataStoreValue(sm, col, 0);
149: }
150:
151: /**
152: * Recursive helper.
153: */
154: private Object toRelationDataStoreValue(OpenJPAStateManager sm,
155: Column col, int idx) {
156: FieldMapping field = findField(col, idx);
157: if (field == null)
158: throw new InternalException();
159:
160: if (field.getHandler() instanceof RelationId)
161: return ((RelationId) field.getStrategy())
162: .toRelationDataStoreValue(sm, col);
163: if (field.getStrategy() instanceof RelationId)
164: return ((RelationId) field.getStrategy())
165: .toRelationDataStoreValue(sm, col);
166: return toRelationDataStoreValue(sm, col, field.getIndex() + 1);
167: }
168:
169: /**
170: * Find the first field mapping that uses the given column starting with
171: * the given field index.
172: */
173: private FieldMapping findField(Column col, int idx) {
174: FieldMapping[] fms = _vm.getEmbeddedMapping()
175: .getFieldMappings();
176: Column[] cols;
177: for (int i = idx; i < fms.length; i++) {
178: if (fms[i].getManagement() != FieldMapping.MANAGE_PERSISTENT)
179: continue;
180: cols = ((Embeddable) fms[i]).getColumns();
181: for (int j = 0; j < cols.length; j++)
182: if (cols[j] == col)
183: return fms[i];
184: }
185: return null;
186: }
187: }
|