blob: 43046164129a0e72deb6233208120b6851526037 [file] [log] [blame]
/*
* 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);
}
}