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.kernel.exps;
020:
021: import java.util.Map;
022:
023: import org.apache.openjpa.jdbc.meta.ClassMapping;
024: import org.apache.openjpa.jdbc.meta.Discriminator;
025: import org.apache.openjpa.jdbc.meta.FieldMapping;
026: import org.apache.openjpa.jdbc.meta.MappingRepository;
027: import org.apache.openjpa.jdbc.sql.Joins;
028: import org.apache.openjpa.jdbc.sql.SQLBuffer;
029: import org.apache.openjpa.jdbc.sql.Select;
030: import org.apache.openjpa.kernel.exps.ExpressionVisitor;
031: import org.apache.openjpa.meta.JavaTypes;
032:
033: /**
034: * Tests whether the given path is an instance of the given class.
035: *
036: * @author Abe White
037: */
038: class InstanceofExpression implements Exp {
039:
040: private final PCPath _path;
041: private final Class _cls;
042:
043: /**
044: * Constructor. Supply path and class to test for.
045: */
046: public InstanceofExpression(PCPath path, Class cls) {
047: _path = path;
048: _cls = cls;
049: }
050:
051: public ExpState initialize(Select sel, ExpContext ctx, Map contains) {
052: // note that we tell the path to go ahead and join to its related
053: // object (if any) in order to access its class indicator
054: ExpState pathState = _path.initialize(sel, ctx, Val.JOIN_REL);
055:
056: // does this path represent a relation? if not, what class
057: // is the field?
058: ClassMapping relMapping = _path.getClassMapping(pathState);
059: Class rel = null;
060: if (relMapping == null) {
061: FieldMapping field = _path.getFieldMapping(pathState);
062: switch (field.getTypeCode()) {
063: case JavaTypes.MAP:
064: if (_path.isKey())
065: rel = field.getKey().getDeclaredType();
066: // no break
067: case JavaTypes.ARRAY:
068: case JavaTypes.COLLECTION:
069: rel = field.getElement().getDeclaredType();
070: break;
071: default:
072: rel = field.getDeclaredType();
073: }
074: } else
075: rel = relMapping.getDescribedType();
076:
077: // if the path represents a relation, get its class indicator and
078: // make sure it's joined down to its base type
079: Discriminator discrim = (relMapping == null || !relMapping
080: .getDescribedType().isAssignableFrom(_cls)) ? null
081: : relMapping.getDiscriminator();
082: ClassMapping mapping = null;
083: Joins joins = pathState.joins;
084: if (discrim != null) {
085: // cache mapping for cast
086: MappingRepository repos = ctx.store.getConfiguration()
087: .getMappingRepositoryInstance();
088: mapping = repos.getMapping(_cls, ctx.store.getContext()
089: .getClassLoader(), false);
090:
091: // if not looking for a PC, don't bother with indicator
092: if (mapping == null
093: || !discrim.hasClassConditions(mapping, true))
094: discrim = null;
095: else {
096: ClassMapping owner = discrim.getClassMapping();
097: ClassMapping from, to;
098: if (relMapping.getDescribedType().isAssignableFrom(
099: owner.getDescribedType())) {
100: from = owner;
101: to = relMapping;
102: } else {
103: from = relMapping;
104: to = owner;
105: }
106:
107: for (; from != null && from != to; from = from
108: .getJoinablePCSuperclassMapping())
109: joins = from.joinSuperclass(joins, false);
110: }
111: }
112: return new InstanceofExpState(joins, pathState, mapping,
113: discrim, rel);
114: }
115:
116: /**
117: * Expression state.
118: */
119: private static class InstanceofExpState extends ExpState {
120:
121: public final ExpState pathState;
122: public final ClassMapping mapping;
123: public final Discriminator discrim;
124: public final Class rel;
125:
126: public InstanceofExpState(Joins joins, ExpState pathState,
127: ClassMapping mapping, Discriminator discrim, Class rel) {
128: super (joins);
129: this .pathState = pathState;
130: this .mapping = mapping;
131: this .discrim = discrim;
132: this .rel = rel;
133: }
134: }
135:
136: public void appendTo(Select sel, ExpContext ctx, ExpState state,
137: SQLBuffer sql) {
138: // if no class indicator or a final class, just append true or false
139: // depending on whether the cast matches the expected type
140: InstanceofExpState istate = (InstanceofExpState) state;
141: if (istate.discrim == null) {
142: if (_cls.isAssignableFrom(istate.rel))
143: sql.append("1 = 1");
144: else
145: sql.append("1 <> 1");
146: } else {
147: ctx.store.loadSubclasses(istate.discrim.getClassMapping());
148: SQLBuffer buf = istate.discrim.getClassConditions(sel,
149: istate.joins, istate.mapping, true);
150: sql.append(buf);
151: }
152: sel.append(sql, istate.joins);
153: }
154:
155: public void selectColumns(Select sel, ExpContext ctx,
156: ExpState state, boolean pks) {
157: InstanceofExpState istate = (InstanceofExpState) state;
158: if (istate.discrim != null)
159: sel.select(istate.discrim.getColumns(), istate.joins);
160: }
161:
162: public void acceptVisit(ExpressionVisitor visitor) {
163: visitor.enter(this);
164: _path.acceptVisit(visitor);
165: visitor.exit(this);
166: }
167: }
|