/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: Apache License, Version 2.0
* See the LICENSE file in the root directory or visit http://www.apache.org/licenses/LICENSE-2.0
*/
package org.hibernate.test.sqm.parser.criteria.tree.path;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.criteria.Path;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import org.hibernate.query.sqm.NotYetImplementedException;
import org.hibernate.query.sqm.domain.SqmNavigable;
import org.hibernate.query.sqm.produce.spi.criteria.JpaExpression;
import org.hibernate.query.sqm.produce.spi.criteria.path.JpaPath;
import org.hibernate.query.sqm.produce.spi.criteria.path.JpaPathSource;
import org.hibernate.test.sqm.parser.criteria.tree.CriteriaBuilderImpl;
import org.hibernate.test.sqm.parser.criteria.tree.expression.AbstractJpaExpressionImpl;
import org.hibernate.test.sqm.parser.criteria.tree.expression.PathTypeExpression;
/**
* Convenience base class for various {@link Path} implementations.
*
* @author Steve Ebersole
*/
public abstract class AbstractPathImpl<X>
extends AbstractJpaExpressionImpl<X>
implements JpaPath<X>, JpaPathSource<X>, Serializable {
private final JpaPathSource pathSource;
private final JpaExpression<Class<? extends X>> typeExpression;
private Map<String,Path> attributePathRegistry;
/**
* Constructs a basic path instance.
*
* @param javaType The java type of this path
* @param criteriaBuilder The criteria builder
* @param pathSource The source (or origin) from which this path originates
*/
@SuppressWarnings({ "unchecked" })
public AbstractPathImpl(
CriteriaBuilderImpl criteriaBuilder,
SqmNavigable sqmNavigable,
Class<X> javaType,
JpaPathSource pathSource) {
super( criteriaBuilder, sqmNavigable, javaType );
this.pathSource = pathSource;
this.typeExpression = new PathTypeExpression( criteriaBuilder(), sqmNavigable, getJavaType(), this );
}
public JpaPathSource getPathSource() {
return pathSource;
}
@Override
public JpaPathSource<?> getParentPath() {
return getPathSource();
}
@Override
@SuppressWarnings({ "unchecked" })
public JpaExpression<Class<? extends X>> type() {
return typeExpression;
}
public abstract String getPathIdentifier();
protected abstract boolean canBeDereferenced();
protected final RuntimeException illegalDereference() {
return new IllegalStateException(
String.format(
"Illegal attempt to dereference path source [%s] of basic type",
getPathIdentifier()
)
);
// String message = "Illegal attempt to dereference path source [";
// if ( source != null ) {
// message += " [" + getPathIdentifier() + "]";
// }
// return new IllegalArgumentException(message);
}
protected final RuntimeException unknownAttribute(String attributeName) {
String message = "Unable to resolve attribute [" + attributeName + "] against path";
JpaPathSource<?> source = getPathSource();
if ( source != null ) {
message += " [" + source.getPathIdentifier() + "]";
}
return new IllegalArgumentException(message);
}
protected final Path resolveCachedAttributePath(String attributeName) {
return attributePathRegistry == null
? null
: attributePathRegistry.get( attributeName );
}
protected final void registerAttributePath(String attributeName, Path path) {
if ( attributePathRegistry == null ) {
attributePathRegistry = new HashMap<String,Path>();
}
attributePathRegistry.put( attributeName, path );
}
@Override
@SuppressWarnings({ "unchecked" })
public <Y> JpaPath<Y> get(SingularAttribute<? super X, Y> attribute) {
// if ( ! canBeDereferenced() ) {
// throw illegalDereference();
// }
//
// SingularAttributePath<Y> path = (SingularAttributePath<Y>) resolveCachedAttributePath( attribute.getName() );
// if ( path == null ) {
// path = new SingularAttributePath<Y>(
// criteriaBuilder(),
// attribute.getJavaType(),
// getPathSourceForSubPaths(),
// attribute
// );
// registerAttributePath( attribute.getName(), path );
// }
// return path;
throw new NotYetImplementedException();
}
protected JpaPathSource getPathSourceForSubPaths() {
return this;
}
@Override
@SuppressWarnings({ "unchecked" })
public <E, C extends Collection<E>> JpaExpression<C> get(PluralAttribute<X, C, E> attribute) {
// if ( ! canBeDereferenced() ) {
// throw illegalDereference();
// }
//
// PluralAttributePath<C> path = (PluralAttributePath<C>) resolveCachedAttributePath( attribute.getName() );
// if ( path == null ) {
// path = new PluralAttributePath<C>( criteriaBuilder(), this, attribute );
// registerAttributePath( attribute.getName(), path );
// }
// return path;
throw new NotYetImplementedException( );
}
@Override
@SuppressWarnings({ "unchecked" })
public <K, V, M extends Map<K, V>> JpaExpression<M> get(MapAttribute<X, K, V> attribute) {
// if ( ! canBeDereferenced() ) {
// throw illegalDereference();
// }
//
// PluralAttributePath path = (PluralAttributePath) resolveCachedAttributePath( attribute.getName() );
// if ( path == null ) {
// path = new PluralAttributePath( criteriaBuilder(), this, attribute );
// registerAttributePath( attribute.getName(), path );
// }
// return path;
throw new NotYetImplementedException( );
}
@Override
@SuppressWarnings({ "unchecked" })
public <Y> JpaPath<Y> get(String attributeName) {
// if ( ! canBeDereferenced() ) {
// throw illegalDereference();
// }
//
// final Attribute attribute = locateAttribute( attributeName );
//
// if ( attribute.isCollection() ) {
// final PluralAttribute<X,Y,?> pluralAttribute = (PluralAttribute<X,Y,?>) attribute;
// if ( PluralAttribute.CollectionType.MAP.equals( pluralAttribute.getCollectionType() ) ) {
// return (PluralAttributePath<Y>) this.<Object,Object,Map<Object, Object>>get( (MapAttribute) pluralAttribute );
// }
// else {
// return (PluralAttributePath<Y>) this.get( (PluralAttribute) pluralAttribute );
// }
// }
// else {
// return get( (SingularAttribute<X,Y>) attribute );
// }
throw new NotYetImplementedException( );
}
/**
* Get the attribute by name from the underlying model. This allows subclasses to
* define exactly how the attribute is derived.
*
* @param attributeName The name of the attribute to locate
*
* @return The attribute; should never return null.
*
* @throws IllegalArgumentException If no such attribute exists
*/
protected final Attribute locateAttribute(String attributeName) {
final Attribute attribute = locateAttributeInternal( attributeName );
if ( attribute == null ) {
throw unknownAttribute( attributeName );
}
return attribute;
}
/**
* Get the attribute by name from the underlying model. This allows subclasses to
* define exactly how the attribute is derived. Called from {@link #locateAttribute}
* which also applies nullness checking for proper error reporting.
*
* @param attributeName The name of the attribute to locate
*
* @return The attribute; may be null.
*
* @throws IllegalArgumentException If no such attribute exists
*/
protected abstract Attribute locateAttributeInternal(String attributeName);
}