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.Collection;
023: import java.util.Map;
024:
025: import org.apache.openjpa.conf.OpenJPAConfiguration;
026: import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
027: import org.apache.openjpa.jdbc.kernel.JDBCStore;
028: import org.apache.openjpa.jdbc.meta.ClassMapping;
029: import org.apache.openjpa.jdbc.meta.FieldMapping;
030: import org.apache.openjpa.jdbc.meta.ValueMapping;
031: import org.apache.openjpa.jdbc.schema.Column;
032: import org.apache.openjpa.jdbc.schema.ForeignKey;
033: import org.apache.openjpa.jdbc.sql.Joins;
034: import org.apache.openjpa.jdbc.sql.Result;
035: import org.apache.openjpa.jdbc.sql.Select;
036: import org.apache.openjpa.jdbc.sql.Union;
037: import org.apache.openjpa.kernel.OpenJPAStateManager;
038: import org.apache.openjpa.lib.util.Localizer;
039: import org.apache.openjpa.meta.JavaTypes;
040: import org.apache.openjpa.util.InternalException;
041: import org.apache.openjpa.util.MetaDataException;
042: import org.apache.openjpa.util.Proxy;
043:
044: /**
045: * Uses an inverse foreign key in the table of the map value to determine
046: * map values. Derives map keys from a field in each value.
047: *
048: * @author Abe White
049: */
050: public class RelationMapInverseKeyFieldStrategy extends
051: RelationToManyInverseKeyFieldStrategy implements
052: LRSMapFieldStrategy {
053:
054: private static final Localizer _loc = Localizer
055: .forPackage(RelationMapInverseKeyFieldStrategy.class);
056:
057: public FieldMapping getFieldMapping() {
058: return field;
059: }
060:
061: public ClassMapping[] getIndependentKeyMappings(boolean traverse) {
062: return ClassMapping.EMPTY_MAPPINGS;
063: }
064:
065: public ClassMapping[] getIndependentValueMappings(boolean traverse) {
066: return getIndependentElementMappings(traverse);
067: }
068:
069: public Column[] getKeyColumns(ClassMapping cls) {
070: return cls.getFieldMapping(
071: field.getKey().getValueMappedByMetaData().getIndex())
072: .getColumns();
073: }
074:
075: public Column[] getValueColumns(ClassMapping cls) {
076: return cls.getPrimaryKeyColumns();
077: }
078:
079: public ForeignKey getJoinForeignKey(ClassMapping cls) {
080: return super .getJoinForeignKey(cls);
081: }
082:
083: public void selectKey(Select sel, ClassMapping key,
084: OpenJPAStateManager sm, JDBCStore store,
085: JDBCFetchConfiguration fetch, Joins joins) {
086: throw new InternalException();
087: }
088:
089: public Object loadKey(OpenJPAStateManager sm, JDBCStore store,
090: JDBCFetchConfiguration fetch, Result res, Joins joins)
091: throws SQLException {
092: throw new InternalException();
093: }
094:
095: public Object deriveKey(JDBCStore store, Object value) {
096: OpenJPAStateManager sm = RelationStrategies.getStateManager(
097: value, store.getContext());
098: return (sm == null) ? null : sm.fetchField(field.getKey()
099: .getValueMappedByMetaData().getIndex(), false);
100: }
101:
102: public Object deriveValue(JDBCStore store, Object key) {
103: return null;
104: }
105:
106: public void selectValue(Select sel, ClassMapping val,
107: OpenJPAStateManager sm, JDBCStore store,
108: JDBCFetchConfiguration fetch, Joins joins) {
109: selectElement(sel, val, store, fetch,
110: JDBCFetchConfiguration.EAGER_NONE, joins);
111: }
112:
113: public Object loadValue(OpenJPAStateManager sm, JDBCStore store,
114: JDBCFetchConfiguration fetch, Result res, Joins joins)
115: throws SQLException {
116: return loadElement(sm, store, fetch, res, joins);
117: }
118:
119: public Result[] getResults(final OpenJPAStateManager sm,
120: final JDBCStore store, final JDBCFetchConfiguration fetch,
121: final int eagerMode, final Joins[] joins, boolean lrs)
122: throws SQLException {
123: ValueMapping val = field.getElementMapping();
124: final ClassMapping[] vals = val.getIndependentTypeMappings();
125: Union union = store.getSQLFactory().newUnion(vals.length);
126: if (fetch.getSubclassFetchMode(val.getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN)
127: union.abortUnion();
128: union.setLRS(lrs);
129: union.select(new Union.Selector() {
130: public void select(Select sel, int idx) {
131: joins[1] = selectAll(sel, vals[idx], sm, store, fetch,
132: eagerMode);
133: }
134: });
135: Result res = union.execute(store, fetch);
136: return new Result[] { res, res };
137: }
138:
139: public Joins joinKeyRelation(Joins joins, ClassMapping key) {
140: return joins;
141: }
142:
143: public Joins joinValueRelation(Joins joins, ClassMapping val) {
144: return joinElementRelation(joins, val);
145: }
146:
147: protected Proxy newLRSProxy() {
148: return new LRSProxyMap(this );
149: }
150:
151: protected void add(JDBCStore store, Object coll, Object obj) {
152: if (obj != null)
153: ((Map) coll).put(deriveKey(store, obj), obj);
154: }
155:
156: protected Collection toCollection(Object val) {
157: return (val == null) ? null : ((Map) val).values();
158: }
159:
160: public void map(boolean adapt) {
161: if (field.getTypeCode() != JavaTypes.MAP)
162: throw new MetaDataException(_loc.get("not-map", field));
163: if (field.getKey().getValueMappedBy() == null)
164: throw new MetaDataException(_loc.get("not-mapped-by-key",
165: field));
166: super .map(adapt);
167: }
168:
169: public Joins joinKey(Joins joins, boolean forceOuter) {
170: return joinRelation(join(joins, forceOuter), forceOuter, false);
171: }
172: }
|