| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.jdbc.kernel.exps; |
| |
| import java.util.Map; |
| |
| import org.apache.openjpa.jdbc.meta.ClassMapping; |
| import org.apache.openjpa.jdbc.meta.Discriminator; |
| import org.apache.openjpa.jdbc.meta.FieldMapping; |
| import org.apache.openjpa.jdbc.meta.MappingRepository; |
| import org.apache.openjpa.jdbc.sql.Joins; |
| import org.apache.openjpa.jdbc.sql.SQLBuffer; |
| import org.apache.openjpa.jdbc.sql.Select; |
| import org.apache.openjpa.kernel.exps.ExpressionVisitor; |
| import org.apache.openjpa.meta.JavaTypes; |
| |
| /** |
| * Tests whether the given path is an instance of the given class. |
| * |
| * @author Abe White |
| */ |
| class InstanceofExpression |
| implements Exp { |
| |
| private final PCPath _path; |
| private final Class _cls; |
| |
| /** |
| * Constructor. Supply path and class to test for. |
| */ |
| public InstanceofExpression(PCPath path, Class cls) { |
| _path = path; |
| _cls = cls; |
| } |
| |
| public ExpState initialize(Select sel, ExpContext ctx, Map contains) { |
| // note that we tell the path to go ahead and join to its related |
| // object (if any) in order to access its class indicator |
| ExpState pathState = _path.initialize(sel, ctx, Val.JOIN_REL); |
| |
| // does this path represent a relation? if not, what class |
| // is the field? |
| ClassMapping relMapping = _path.getClassMapping(pathState); |
| Class rel = null; |
| if (relMapping == null) { |
| FieldMapping field = _path.getFieldMapping(pathState); |
| switch (field.getTypeCode()) { |
| case JavaTypes.MAP: |
| if (_path.isKey()) |
| rel = field.getKey().getDeclaredType(); |
| // no break |
| case JavaTypes.ARRAY: |
| case JavaTypes.COLLECTION: |
| rel = field.getElement().getDeclaredType(); |
| break; |
| default: |
| rel = field.getDeclaredType(); |
| } |
| } else |
| rel = relMapping.getDescribedType(); |
| |
| // if the path represents a relation, get its class indicator and |
| // make sure it's joined down to its base type |
| Discriminator discrim = (relMapping == null |
| || !relMapping.getDescribedType().isAssignableFrom(_cls)) |
| ? null : relMapping.getDiscriminator(); |
| ClassMapping mapping = null; |
| Joins joins = pathState.joins; |
| if (discrim != null) { |
| // cache mapping for cast |
| MappingRepository repos = ctx.store.getConfiguration(). |
| getMappingRepositoryInstance(); |
| mapping = repos.getMapping(_cls, ctx.store.getContext(). |
| getClassLoader(), false); |
| |
| // if not looking for a PC, don't bother with indicator |
| if (mapping == null || !discrim.hasClassConditions(mapping, true)) |
| discrim = null; |
| else { |
| ClassMapping owner = discrim.getClassMapping(); |
| ClassMapping from, to; |
| if (relMapping.getDescribedType().isAssignableFrom |
| (owner.getDescribedType())) { |
| from = owner; |
| to = relMapping; |
| } else { |
| from = relMapping; |
| to = owner; |
| } |
| |
| for (; from != null && from != to; |
| from = from.getJoinablePCSuperclassMapping()) |
| joins = from.joinSuperclass(joins, false); |
| } |
| } |
| return new InstanceofExpState(joins, pathState, mapping, discrim, rel); |
| } |
| |
| /** |
| * Expression state. |
| */ |
| private static class InstanceofExpState |
| extends ExpState { |
| |
| public final ExpState pathState; |
| public final ClassMapping mapping; |
| public final Discriminator discrim; |
| public final Class rel; |
| |
| public InstanceofExpState(Joins joins, ExpState pathState, |
| ClassMapping mapping, Discriminator discrim, Class rel) { |
| super(joins); |
| this.pathState = pathState; |
| this.mapping = mapping; |
| this.discrim = discrim; |
| this.rel = rel; |
| } |
| } |
| |
| public void appendTo(Select sel, ExpContext ctx, ExpState state, |
| SQLBuffer sql) { |
| // if no class indicator or a final class, just append true or false |
| // depending on whether the cast matches the expected type |
| InstanceofExpState istate = (InstanceofExpState) state; |
| if (istate.discrim == null) { |
| if (_cls.isAssignableFrom(istate.rel)) |
| sql.append("1 = 1"); |
| else |
| sql.append("1 <> 1"); |
| } else { |
| ctx.store.loadSubclasses(istate.discrim.getClassMapping()); |
| SQLBuffer buf = istate.discrim.getClassConditions(sel, |
| istate.joins, istate.mapping, true); |
| sql.append(buf); |
| } |
| sel.append(sql, istate.joins); |
| } |
| |
| public void selectColumns(Select sel, ExpContext ctx, ExpState state, |
| boolean pks) { |
| InstanceofExpState istate = (InstanceofExpState) state; |
| if (istate.discrim != null) |
| sel.select(istate.discrim.getColumns(), istate.joins); |
| } |
| |
| public void acceptVisit(ExpressionVisitor visitor) { |
| visitor.enter(this); |
| _path.acceptVisit(visitor); |
| visitor.exit(this); |
| } |
| } |
| |