diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/AbstractBasicPluralJoin.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/AbstractBasicPluralJoin.java new file mode 100644 index 0000000000..8abc51b4f8 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/AbstractBasicPluralJoin.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.CollectionJoin; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.MapJoin; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.PluralJoin; +import javax.persistence.criteria.SetJoin; +import javax.persistence.metamodel.CollectionAttribute; +import javax.persistence.metamodel.ListAttribute; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SingularAttribute; + +/** + * Convenience base class for all basic collection joins. Mainly we handle the fact that + * this path cannot be further de-referenced. + * + * @author Steve Ebersole + */ +public abstract class AbstractBasicPluralJoin extends JoinImpl implements PluralJoin { + + public AbstractBasicPluralJoin( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + PluralAttribute joinProperty, + JoinType joinType) { + super(queryBuilder, javaType, lhs, joinProperty, joinType); + } + + @Override + public PluralAttribute getModel() { + return ( PluralAttribute ) super.getAttribute(); + } + + @Override + public Expression> type(){ + throw new BasicPathUsageException( "type() is not applicable to primitive paths.", getAttribute() ); + } + + @Override + public Path get(SingularAttribute attribute){ + throw illegalDereference(); + } + + private BasicPathUsageException illegalDereference() { + return new BasicPathUsageException( "Basic collection elements cannot be de-referenced", getAttribute() ); + } + + @Override + public > Expression get(PluralAttribute collection){ + throw illegalDereference(); + } + + @Override + public > Expression get(MapAttribute map){ + throw illegalDereference(); + } + + @Override + public Path get(String attName) { + throw illegalDereference(); + } + + @Override + public Join join(SingularAttribute attribute, JoinType jt) { + throw illegalJoin(); + } + + private BasicPathUsageException illegalJoin() { + return new BasicPathUsageException( "Basic collection cannot be source of a join", getAttribute() ); + } + + @Override + public CollectionJoin join(CollectionAttribute collection, JoinType jt) { + throw illegalJoin(); + } + + @Override + public SetJoin join(javax.persistence.metamodel.SetAttribute set, JoinType jt) { + throw illegalJoin(); + } + + @Override + public ListJoin join(ListAttribute list, JoinType jt) { + throw illegalJoin(); + } + + @Override + public MapJoin join(MapAttribute map, JoinType jt) { + throw illegalJoin(); + } + + @Override + public Join join(String attributeName, JoinType jt) { + throw illegalJoin(); + } + + @Override + public CollectionJoin joinCollection(String attributeName, JoinType jt) { + throw illegalJoin(); + } + + @Override + public ListJoin joinList(String attributeName, JoinType jt) { + throw illegalJoin(); + } + + @Override + public MapJoin joinMap(String attributeName, JoinType jt) { + throw illegalJoin(); + } + + @Override + public SetJoin joinSet(String attributeName, JoinType jt) { + throw illegalJoin(); + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicCollectionJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicCollectionJoinImpl.java new file mode 100644 index 0000000000..c307a5967b --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicCollectionJoinImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.CollectionJoin; +import javax.persistence.criteria.JoinType; +import javax.persistence.metamodel.CollectionAttribute; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.Collection}, whose elements + * are basic type. + * + * @author Steve Ebersole + */ +public class BasicCollectionJoinImpl + extends AbstractBasicPluralJoin,E> + implements CollectionJoin { + + public BasicCollectionJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + CollectionAttribute joinProperty, + JoinType joinType) { + super(queryBuilder, javaType, lhs, joinProperty, joinType); + } + + @Override + public CollectionAttribute getModel() { + return (CollectionAttribute) super.getAttribute(); + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicListJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicListJoinImpl.java new file mode 100644 index 0000000000..14ae3a5971 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicListJoinImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.ListJoin; +import javax.persistence.metamodel.ListAttribute; +import org.hibernate.ejb.criteria.expression.ListIndexExpression; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.List}, whose elements + * are basic type. + * + * @author Steve Ebersole + */ +public class BasicListJoinImpl + extends AbstractBasicPluralJoin,E> + implements ListJoin { + + public BasicListJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + ListAttribute joinProperty, + JoinType joinType) { + super(queryBuilder, javaType, lhs, joinProperty, joinType); + } + + @Override + public ListAttribute getAttribute() { + return (ListAttribute) super.getAttribute(); + } + + @Override + public ListAttribute getModel() { + return getAttribute(); + } + + public Expression index() { + return new ListIndexExpression( queryBuilder(), getAttribute() ); + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicMapJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicMapJoinImpl.java new file mode 100644 index 0000000000..27f3bf4c95 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicMapJoinImpl.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import java.util.Map; +import java.util.Map.Entry; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.MapJoin; +import javax.persistence.criteria.Path; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.Type.PersistenceType; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.Map}, whose elements + * are associations. + * + * @param The map owner + * @param The map key + * @param The map value + * + * @author Steve Ebersole + */ +public class BasicMapJoinImpl + extends AbstractBasicPluralJoin,V> + implements MapJoin { + + public BasicMapJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + MapAttribute joinProperty, + JoinType joinType) { + super( queryBuilder, javaType, lhs, joinProperty, joinType ); + } + + @Override + public MapAttribute getAttribute() { + return (MapAttribute) super.getAttribute(); + } + + @Override + public MapAttribute getModel() { + return getAttribute(); + } + + /** + * {@inheritDoc} + */ + public Join, K> joinKey() { + return joinKey( DEFAULT_JOIN_TYPE ); + } + + /** + * {@inheritDoc} + */ + public Join, K> joinKey(JoinType jt) { + if ( PersistenceType.BASIC.equals( getAttribute().getKeyType().getPersistenceType() ) ) { + throw new BasicPathUsageException( "Cannot join to map key of basic type", getAttribute() ); + } + + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final MapKeyHelpers.MapPath source = new MapKeyHelpers.MapPath( + queryBuilder(), + getAttribute().getJavaType(), + this, + getAttribute(), + getParentPath().getModel() + ); + final MapKeyHelpers.MapKeyAttribute attribute = new MapKeyHelpers.MapKeyAttribute( queryBuilder(), getAttribute() ); + final Join, K> join = new MapKeyHelpers.MapKeyJoin( + queryBuilder(), + source, + attribute, + jt + ); + + return join; + } + + + /** + * {@inheritDoc} + */ + @SuppressWarnings({ "unchecked" }) + public Path key() { + final MapKeyHelpers.MapPath source = new MapKeyHelpers.MapPath( + queryBuilder(), + getAttribute().getJavaType(), + this, + getAttribute(), + getParentPath().getModel() + ); + final MapKeyHelpers.MapKeyAttribute attribute = new MapKeyHelpers.MapKeyAttribute( queryBuilder(), getAttribute() ); + return new MapKeyHelpers.MapKeyPath( queryBuilder(), source, attribute ); + } + + /** + * {@inheritDoc} + */ + public Path value() { + // API docs explicitly say value() should simply return this; + return this; + } + + /** + * {@inheritDoc} + */ + public Expression> entry() { + // TODO : ??? + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicPathUsageException.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicPathUsageException.java new file mode 100644 index 0000000000..584ba7967d --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicPathUsageException.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.metamodel.Attribute; + +/** + * Represents an incorrect usage of a basic path. Generally this means an attempt to + * de-reference a basic attribute path. + * + * @author Steve Ebersole + */ +public class BasicPathUsageException extends RuntimeException { + private final Attribute attribute; + + /** + * Construct the usage exception. + * + * @param message An error message describing the incorrect usage. + * @param attribute The basic attribute involved. + */ + public BasicPathUsageException(String message, Attribute attribute) { + super( message ); + this.attribute = attribute; + } + + /** + * Construct the usage exception. + * + * @param message An error message describing the incorrect usage. + * @param cause An underlying cause. + * @param attribute The basic attribute involved. + */ + public BasicPathUsageException(String message, Throwable cause, Attribute attribute) { + super( message, cause ); + this.attribute = attribute; + } + + public Attribute getAttribute() { + return attribute; + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicSetJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicSetJoinImpl.java new file mode 100644 index 0000000000..987711cf7e --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/BasicSetJoinImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.SetJoin; +import javax.persistence.metamodel.SetAttribute; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.Set}, whose elements + * are basic type. + * + * @author Steve Ebersole + */ +public class BasicSetJoinImpl + extends AbstractBasicPluralJoin,E> + implements SetJoin { + + public BasicSetJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + SetAttribute joinProperty, + JoinType joinType) { + super( queryBuilder, javaType, lhs, joinProperty, joinType ); + } + + @Override + public SetAttribute getModel() { + return (SetAttribute) super.getAttribute(); + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/CollectionJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/CollectionJoinImpl.java new file mode 100644 index 0000000000..5bbdaff0ac --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/CollectionJoinImpl.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.CollectionJoin; +import javax.persistence.criteria.JoinType; +import javax.persistence.metamodel.CollectionAttribute; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.Collection}, whose elements + * are associations. + * + * @author Steve Ebersole + */ +public class CollectionJoinImpl extends JoinImpl implements CollectionJoin { + + public CollectionJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + CollectionAttribute joinProperty, + JoinType joinType) { + super(queryBuilder, javaType, lhs, joinProperty, joinType); + } + + @Override + public CollectionAttribute getModel() { + return (CollectionAttribute) super.getAttribute(); + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaSubqueryImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaSubqueryImpl.java index 51a1771509..e9bfae5aa7 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaSubqueryImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaSubqueryImpl.java @@ -34,14 +34,14 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.SetJoin; import javax.persistence.criteria.Subquery; import javax.persistence.metamodel.EntityType; -import org.hibernate.ejb.criteria.expression.AbstractExpression; +import org.hibernate.ejb.criteria.expression.ExpressionImpl; /** * TODO : javadoc * * @author Steve Ebersole */ -public class CriteriaSubqueryImpl extends AbstractExpression implements Subquery { +public class CriteriaSubqueryImpl extends ExpressionImpl implements Subquery { private final AbstractQuery parent; private final QueryStructure queryStructure; diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/FromImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/FromImpl.java index 53c425c7c5..e74022603a 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/FromImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/FromImpl.java @@ -36,18 +36,19 @@ import javax.persistence.criteria.Path; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Fetch; import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Attribute.PersistentAttributeType; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.CollectionAttribute; import javax.persistence.metamodel.SetAttribute; import javax.persistence.metamodel.ListAttribute; import javax.persistence.metamodel.MapAttribute; -import javax.persistence.metamodel.Bindable; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.PluralAttribute.CollectionType; import javax.persistence.metamodel.Type.PersistenceType; -import org.hibernate.ejb.criteria.expression.AbstractExpression; +import org.hibernate.ejb.criteria.expression.CollectionExpression; import org.hibernate.ejb.criteria.expression.EntityTypeExpression; /** @@ -69,7 +70,7 @@ public abstract class FromImpl extends PathImpl implements From { * @param entityType */ protected FromImpl(QueryBuilderImpl queryBuilder, EntityType entityType) { - super( queryBuilder, entityType.getBindableJavaType(), null, entityType ); + super( queryBuilder, entityType.getBindableJavaType(), null, null, entityType ); this.type = new EntityTypeExpression( queryBuilder, entityType.getBindableJavaType() ); } @@ -77,10 +78,10 @@ public abstract class FromImpl extends PathImpl implements From { QueryBuilderImpl queryBuilder, Class javaType, PathImpl origin, - Bindable model, - Expression> type) { - super( queryBuilder, javaType, origin, model ); - this.type = type; + Attribute attribute, + ManagedType model) { + super( queryBuilder, javaType, origin, attribute, model ); + this.type = new EntityTypeExpression( queryBuilder, model.getJavaType() ); } @Override @@ -88,6 +89,18 @@ public abstract class FromImpl extends PathImpl implements From { return type; } + /** + * Get the attribute by name from the underlying model. This alows subclasses to + * define exactly how the attribute is derived. + * + * @param name The attribute name + * + * @return The attribute. + * + * @throws IllegalArgumentException If no such attribute is found (follows exception type from {@link ManagedType}). + */ + protected abstract Attribute getAttribute(String name); + // JOINS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -111,6 +124,10 @@ public abstract class FromImpl extends PathImpl implements From { return joins; } + protected void addJoin(Join join) { + getJoinsInternal().add( join ); + } + /** * {@inheritDoc} */ @@ -123,9 +140,25 @@ public abstract class FromImpl extends PathImpl implements From { */ public Join join(SingularAttribute attribute, JoinType jt) { if ( PersistenceType.BASIC.equals( attribute.getType().getPersistenceType() ) ) { - throw new IllegalStateException( "Cannot join to basic type" ); + throw new BasicPathUsageException( "Cannot join to attribute of basic type", attribute ); } - throw new UnsupportedOperationException( "Not yet implemented!" ); + + // TODO : runtime check that the attribute in fact belongs to this From's model/bindable + + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final Class attributeType = attribute.getBindableJavaType(); + final JoinImpl join = new JoinImpl( + queryBuilder(), + attributeType, + this, + attribute, + jt + ); + joins.add( join ); + return join; } /** @@ -139,8 +172,36 @@ public abstract class FromImpl extends PathImpl implements From { * {@inheritDoc} */ public CollectionJoin join(CollectionAttribute collection, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final Class attributeType = collection.getBindableJavaType(); + final CollectionJoin join; + if ( isBasicCollection( collection ) ) { + join = new BasicCollectionJoinImpl( + queryBuilder(), + attributeType, + this, + collection, + jt + ); + } + else { + join = new CollectionJoinImpl( + queryBuilder(), + attributeType, + this, + collection, + jt + ); + } + joins.add( join ); + return join; + } + + private boolean isBasicCollection(PluralAttribute collection) { + return PersistenceType.BASIC.equals( collection.getElementType().getPersistenceType() ); } /** @@ -154,8 +215,20 @@ public abstract class FromImpl extends PathImpl implements From { * {@inheritDoc} */ public SetJoin join(SetAttribute set, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final Class attributeType = set.getBindableJavaType(); + final SetJoin join; + if ( isBasicCollection( set ) ) { + join = new BasicSetJoinImpl( queryBuilder(), attributeType, this, set, jt ); + } + else { + join = new SetJoinImpl( queryBuilder(), attributeType, this, set, jt ); + } + joins.add( join ); + return join; } /** @@ -169,8 +242,20 @@ public abstract class FromImpl extends PathImpl implements From { * {@inheritDoc} */ public ListJoin join(ListAttribute list, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final Class attributeType = list.getBindableJavaType(); + final ListJoin join; + if ( isBasicCollection( list ) ) { + join = new BasicListJoinImpl( queryBuilder(), attributeType, this, list, jt ); + } + else { + join = new ListJoinImpl( queryBuilder(), attributeType, this, list, jt ); + } + joins.add( join ); + return join; } /** @@ -184,83 +269,152 @@ public abstract class FromImpl extends PathImpl implements From { * {@inheritDoc} */ public MapJoin join(MapAttribute map, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final Class attributeType = map.getBindableJavaType(); + final MapJoin join; + if ( isBasicCollection( map ) ) { + join = new BasicMapJoinImpl( queryBuilder(), attributeType, this, map, jt ); + } + else { + join = new MapJoinImpl( queryBuilder(), attributeType, this, map, jt ); + } + joins.add( join ); + return join; } /** * {@inheritDoc} */ - public Join join(String attributeName) { + public Join join(String attributeName) { return join( attributeName, DEFAULT_JOIN_TYPE ); } /** * {@inheritDoc} */ - public Join join(String attributeName, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + public Join join(String attributeName, JoinType jt) { + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final Attribute attribute = (Attribute) getAttribute( attributeName ); + if ( attribute.isCollection() ) { + final PluralAttribute pluralAttribute = ( PluralAttribute ) attribute; + if ( CollectionType.COLLECTION.equals( pluralAttribute.getCollectionType() ) ) { + return join( (CollectionAttribute) attribute, jt ); + } + else if ( CollectionType.LIST.equals( pluralAttribute.getCollectionType() ) ) { + return join( (ListAttribute) attribute, jt ); + } + else if ( CollectionType.SET.equals( pluralAttribute.getCollectionType() ) ) { + return join( (SetAttribute) attribute, jt ); + } + else { + return join( (MapAttribute) attribute, jt ); + } + } + else { + return join( (SingularAttribute)attribute, jt ); + } } /** * {@inheritDoc} */ - public CollectionJoin joinCollection(String attributeName) { + public CollectionJoin joinCollection(String attributeName) { return joinCollection( attributeName, DEFAULT_JOIN_TYPE ); } /** * {@inheritDoc} */ - public CollectionJoin joinCollection(String attributeName, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + public CollectionJoin joinCollection(String attributeName, JoinType jt) { + final Attribute attribute = (Attribute) getAttribute( attributeName ); + if ( ! attribute.isCollection() ) { + throw new IllegalArgumentException( "Requested attribute was not a collection" ); + } + + final PluralAttribute pluralAttribute = ( PluralAttribute ) attribute; + if ( ! CollectionType.COLLECTION.equals( pluralAttribute.getCollectionType() ) ) { + throw new IllegalArgumentException( "Requested attribute was not a collection" ); + } + + return join( (CollectionAttribute) attribute, jt ); } /** * {@inheritDoc} */ - public SetJoin joinSet(String attributeName) { + public SetJoin joinSet(String attributeName) { return joinSet( attributeName, DEFAULT_JOIN_TYPE ); } /** * {@inheritDoc} */ - public SetJoin joinSet(String attributeName, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + public SetJoin joinSet(String attributeName, JoinType jt) { + final Attribute attribute = (Attribute) getAttribute( attributeName ); + if ( ! attribute.isCollection() ) { + throw new IllegalArgumentException( "Requested attribute was not a set" ); + } + + final PluralAttribute pluralAttribute = ( PluralAttribute ) attribute; + if ( ! CollectionType.SET.equals( pluralAttribute.getCollectionType() ) ) { + throw new IllegalArgumentException( "Requested attribute was not a set" ); + } + + return join( (SetAttribute) attribute, jt ); } /** * {@inheritDoc} */ - public ListJoin joinList(String attributeName) { + public ListJoin joinList(String attributeName) { return joinList( attributeName, DEFAULT_JOIN_TYPE ); } /** * {@inheritDoc} */ - public ListJoin joinList(String attributeName, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + public ListJoin joinList(String attributeName, JoinType jt) { + final Attribute attribute = (Attribute) getAttribute( attributeName ); + if ( ! attribute.isCollection() ) { + throw new IllegalArgumentException( "Requested attribute was not a list" ); + } + + final PluralAttribute pluralAttribute = ( PluralAttribute ) attribute; + if ( ! CollectionType.LIST.equals( pluralAttribute.getCollectionType() ) ) { + throw new IllegalArgumentException( "Requested attribute was not a list" ); + } + + return join( (ListAttribute) attribute, jt ); } /** * {@inheritDoc} */ - public MapJoin joinMap(String attributeName) { + public MapJoin joinMap(String attributeName) { return joinMap( attributeName, DEFAULT_JOIN_TYPE ); } /** * {@inheritDoc} */ - public MapJoin joinMap(String attributeName, JoinType jt) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + public MapJoin joinMap(String attributeName, JoinType jt) { + final Attribute attribute = (Attribute) getAttribute( attributeName ); + if ( ! attribute.isCollection() ) { + throw new IllegalArgumentException( "Requested attribute was not a map" ); + } + + final PluralAttribute pluralAttribute = ( PluralAttribute ) attribute; + if ( ! CollectionType.MAP.equals( pluralAttribute.getCollectionType() ) ) { + throw new IllegalArgumentException( "Requested attribute was not a map" ); + } + + return join( (MapAttribute) attribute, jt ); } @@ -316,23 +470,46 @@ public abstract class FromImpl extends PathImpl implements From { // PATH HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - public Path get(SingularAttribute ySingularAttribute) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + @Override + public Path get(SingularAttribute attribute) { + if ( PersistentAttributeType.BASIC.equals( attribute.getPersistentAttributeType() ) ) { + return new PathImpl( queryBuilder(), attribute.getJavaType(), this, attribute, attribute.getBindableType() ); + } + else { + return join( attribute ); + } } + @Override public > Expression get(PluralAttribute collection) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + return new CollectionExpression( queryBuilder(), collection.getJavaType(), collection ); } + @Override public > Expression get(MapAttribute map) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + return ( Expression ) new CollectionExpression>( queryBuilder(), map.getJavaType(), map ); } + @Override public Path get(String attributeName) { - // TODO : implement - throw new UnsupportedOperationException( "Not yet implemented!" ); + Attribute attribute = getAttribute( attributeName ); + if ( attribute.isCollection() ) { + final PluralAttribute pluralAttribute = (PluralAttribute) attribute; + if ( CollectionType.COLLECTION.equals( pluralAttribute.getCollectionType() ) ) { + return join( (CollectionAttribute) attribute ); + } + else if ( CollectionType.LIST.equals( pluralAttribute.getCollectionType() ) ) { + return join( (ListAttribute) attribute ); + } + else if ( CollectionType.SET.equals( pluralAttribute.getCollectionType() ) ) { + return join( (SetAttribute) attribute ); + } + else { + return join( (MapAttribute) attribute ); + } + } + else { + return get( (SingularAttribute) attribute ); + } } } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/JoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/JoinImpl.java new file mode 100644 index 0000000000..c02eecebe7 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/JoinImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.ManagedType; + +/** + * Models a non-collection property join. + * + * @author Steve Ebersole + */ +public class JoinImpl extends FromImpl implements Join { + // TODO : keep track or whether any non-identifier properties get dereferenced + // for join optimization like in HQL + + // TODO : do we need (or is it easier with) a separate "component join impl"? + + // TODO : cleanup these ctors, ugh... + + private final ManagedType managedType; + private final JoinType joinType; + + public JoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + Attribute joinProperty, + JoinType joinType) { + super( + queryBuilder, + javaType, + lhs, + joinProperty, + (ManagedType)queryBuilder.getEntityManagerFactory().getMetamodel().type( javaType ) + ); + this.managedType = (ManagedType) getModel(); + this.joinType = joinType; + } + + /** + * {@inheritDoc} + */ + public From getParent() { + // AFAICT, only "froms" (specifically roots and joins) can be the parent of a join. + return ( From ) getParentPath(); + } + + @Override + public Attribute getAttribute() { + return (Attribute) super.getAttribute(); + } + + /** + * {@inheritDoc} + */ + public JoinType getJoinType() { + return joinType; + } + + @Override + protected Attribute getAttribute(String name) { + return (Attribute) managedType.getAttribute( name ); + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/ListJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/ListJoinImpl.java new file mode 100644 index 0000000000..487aaad7dd --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/ListJoinImpl.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.ListJoin; +import javax.persistence.metamodel.ListAttribute; +import org.hibernate.ejb.criteria.expression.ListIndexExpression; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.List}, whose elements + * are associations. + * + * @author Steve Ebersole + */ +public class ListJoinImpl extends JoinImpl implements ListJoin { + public ListJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + ListAttribute joinProperty, + JoinType joinType) { + super( queryBuilder, javaType, lhs, joinProperty, joinType ); + } + + @Override + public ListAttribute getAttribute() { + return (ListAttribute) super.getAttribute(); + } + + @Override + public ListAttribute getModel() { + return (ListAttribute) getAttribute(); + } + + public Expression index() { + return new ListIndexExpression( queryBuilder(), getAttribute() ); + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/MapJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/MapJoinImpl.java new file mode 100644 index 0000000000..0f2370c607 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/MapJoinImpl.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import java.util.Map; +import java.util.Map.Entry; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.MapJoin; +import javax.persistence.criteria.Path; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.Type.PersistenceType; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.Map}, whose elements + * are associations. + * + * @author Steve Ebersole + */ +public class MapJoinImpl + extends JoinImpl + implements MapJoin { + + public MapJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + MapAttribute joinProperty, + JoinType joinType) { + super(queryBuilder, javaType, lhs, joinProperty, joinType); + } + + @Override + public MapAttribute getAttribute() { + return (MapAttribute) super.getAttribute(); + } + + @Override + public MapAttribute getModel() { + return getAttribute(); + } + + /** + * {@inheritDoc} + */ + public Join, K> joinKey() { + return joinKey( DEFAULT_JOIN_TYPE ); + } + + /** + * {@inheritDoc} + */ + public Join, K> joinKey(JoinType jt) { + if ( PersistenceType.BASIC.equals( getAttribute().getKeyType().getPersistenceType() ) ) { + throw new BasicPathUsageException( "Cannot join to map key of basic type", getAttribute() ); + } + + if ( jt.equals( JoinType.RIGHT ) ) { + throw new UnsupportedOperationException( "RIGHT JOIN not supported" ); + } + + final MapKeyHelpers.MapPath mapKeySource = new MapKeyHelpers.MapPath( + queryBuilder(), + getAttribute().getJavaType(), + this, + getAttribute(), + getParentPath().getModel() + ); + final MapKeyHelpers.MapKeyAttribute mapKeyAttribute = new MapKeyHelpers.MapKeyAttribute( queryBuilder(), getAttribute() ); + final Join, K> join = new MapKeyHelpers.MapKeyJoin( + queryBuilder(), + mapKeySource, + mapKeyAttribute, + jt + ); + + return join; + } + + /** + * {@inheritDoc} + */ + public Path key() { + final MapKeyHelpers.MapPath mapKeySource = new MapKeyHelpers.MapPath( + queryBuilder(), + getAttribute().getJavaType(), + this, + getAttribute(), + getParentPath().getModel() + ); + final MapKeyHelpers.MapKeyAttribute mapKeyAttribute = new MapKeyHelpers.MapKeyAttribute( queryBuilder(), getAttribute() ); + return new MapKeyHelpers.MapKeyPath( queryBuilder(), mapKeySource, mapKeyAttribute ); + } + + /** + * {@inheritDoc} + */ + public Path value() { + return this; + } + + /** + * {@inheritDoc} + */ + public Expression> entry() { + // TODO : ??? + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/MapKeyHelpers.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/MapKeyHelpers.java new file mode 100644 index 0000000000..1c168a4329 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/MapKeyHelpers.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import java.lang.reflect.Member; +import java.util.Map; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.MapJoin; +import javax.persistence.criteria.Path; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Bindable.BindableType; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type.PersistenceType; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.type.Type; + +/** + * {@link MapJoin} defines a number of methods which require {@link Path}, {@link Join} and {@link Attribute} + * implementations which do not fit nicely into the generic signatures it defines for everything else (mainly + * in terms of dealing with the map key). The implementations found here provide that bridge. + * + * @author Steve Ebersole + */ +public class MapKeyHelpers { + + /** + * Represents a join to the key of a map attribute. Obviously the map key must be an + * entity or component type. + * + * @param The type of the map key + * @param The type of the map value + */ + public static class MapKeyJoin extends JoinImpl, K> implements Join, K> { + public MapKeyJoin(QueryBuilderImpl queryBuilder, MapPath source, MapKeyAttribute attribute, JoinType jt) { + super( + queryBuilder, + attribute.getJavaType(), + source, + attribute, + jt + ); + } + } + + /** + * Models a path to a map key. + * + * @param The type of the map key. + */ + public static class MapKeyPath extends PathImpl implements Path { + public MapKeyPath( + QueryBuilderImpl queryBuilder, + MapPath source, + MapKeyAttribute attribute) { + super( queryBuilder, attribute.getJavaType(), source, attribute, attribute.getType() ); + } + } + + /** + * Defines a {@link Path} resulting in a map attribute. This can then be used as the + * parent/origin/source for referencing the map-key. + * + * @param The map key type + * @param The map value type + */ + public static class MapPath extends PathImpl> implements Path> { + private final MapJoin mapJoin; + + public MapPath( + QueryBuilderImpl queryBuilder, + Class> javaType, + MapJoin mapJoin, + MapAttribute attribute, + Object model) { + super(queryBuilder, javaType, null, attribute, model); + this.mapJoin = mapJoin; + } + + @Override + public MapAttribute getAttribute() { + return (MapAttribute) super.getAttribute(); + } + + @Override + public PathImpl getParentPath() { + return (PathImpl) mapJoin; + } + + } + + /** + * Defines an {@link Attribute} modelling of a map-key. + *

+ * TODO : Ideally something like this needs to be part of the metamodel package + * + * @param The type of the map key + */ + public static class MapKeyAttribute implements SingularAttribute,K> { + private final MapAttribute attribute; + private final CollectionPersister mapPersister; + private final Type mapKeyType; + private final javax.persistence.metamodel.Type jpaType; + private final BindableType jpaBindableType; + private final Class jpaBinableJavaType; + + public MapKeyAttribute(QueryBuilderImpl queryBuilder, MapAttribute attribute) { + this.attribute = attribute; + this.jpaType = attribute.getKeyType(); + this.jpaBinableJavaType = attribute.getKeyJavaType(); + this.jpaBindableType = PersistenceType.ENTITY.equals( jpaType.getPersistenceType() ) + ? BindableType.ENTITY_TYPE + : BindableType.SINGULAR_ATTRIBUTE; + + String guessedRoleName = determineRole( attribute ); + SessionFactoryImplementor sfi = (SessionFactoryImplementor) + queryBuilder.getEntityManagerFactory().getSessionFactory(); + mapPersister = sfi.getCollectionPersister( guessedRoleName ); + if ( mapPersister == null ) { + throw new IllegalStateException( "Could not locate collection persister [" + guessedRoleName + "]" ); + } + mapKeyType = mapPersister.getIndexType(); + if ( mapKeyType == null ) { + throw new IllegalStateException( "Could not determine map-key type [" + guessedRoleName + "]" ); + } + } + + private String determineRole(MapAttribute attribute) { + return attribute.getDeclaringType().getJavaType().getName() + + '.' + attribute.getName(); + } + + /** + * {@inheritDoc} + */ + public String getName() { + // TODO : ??? + return "map-key"; + } + + /** + * {@inheritDoc} + */ + public PersistentAttributeType getPersistentAttributeType() { + if ( mapKeyType.isEntityType() ) { + return PersistentAttributeType.MANY_TO_ONE; + } + else if ( mapKeyType.isComponentType() ) { + return PersistentAttributeType.EMBEDDED; + } + else { + return PersistentAttributeType.BASIC; + } + } + + /** + * {@inheritDoc} + */ + public ManagedType> getDeclaringType() { + // TODO : ??? + return null; + } + + /** + * {@inheritDoc} + */ + public Class getJavaType() { + return attribute.getKeyJavaType(); + } + + /** + * {@inheritDoc} + */ + public Member getJavaMember() { + // TODO : ??? + return null; + } + + /** + * {@inheritDoc} + */ + public boolean isAssociation() { + return mapKeyType.isEntityType(); + } + + /** + * {@inheritDoc} + */ + public boolean isCollection() { + return false; + } + + public boolean isId() { + return false; + } + + public boolean isVersion() { + return false; + } + + public boolean isOptional() { + return false; + } + + public javax.persistence.metamodel.Type getType() { + return jpaType; + } + + public BindableType getBindableType() { + return jpaBindableType; + } + + public Class getBindableJavaType() { + return jpaBinableJavaType; + } + } + + /** + * Disallow instantiation + */ + private MapKeyHelpers() { + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/PathImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/PathImpl.java index b3b07898c0..81eab37319 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/PathImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/PathImpl.java @@ -26,29 +26,41 @@ import java.util.Map; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; +import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Bindable; -import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.MapAttribute; import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SingularAttribute; -import org.hibernate.ejb.criteria.expression.AbstractExpression; +import org.hibernate.ejb.criteria.expression.ExpressionImpl; /** - * A {@link Path} models an individual portion of a join expression. + * A {@link Path} models an individual portion of a path expression. * * @author Steve Ebersole */ -public class PathImpl extends AbstractExpression implements Path { +public class PathImpl extends ExpressionImpl implements Path { private final PathImpl origin; - private Bindable model; + private final Attribute attribute; + private Object model; + /** + * Constructs a path. + * + * @param queryBuilder The delegate for building query components. + * @param javaType The java type of this path, + * @param origin The source ("lhs") of this path. + * @param attribute The attribute defining this path element. + * @param model The corresponding model of this path. + */ protected PathImpl( QueryBuilderImpl queryBuilder, Class javaType, PathImpl origin, - Bindable model) { + Attribute attribute, + Object model) { super( queryBuilder, javaType ); this.origin = origin; + this.attribute = attribute; this.model = model; } @@ -59,6 +71,10 @@ public class PathImpl extends AbstractExpression implements Path { return origin; } + public Attribute getAttribute() { + return attribute; + } + /** * {@inheritDoc} */ @@ -66,7 +82,7 @@ public class PathImpl extends AbstractExpression implements Path { if ( model == null ) { throw new IllegalStateException( this + " represents a basic path and not a bindable" ); } - return model; + return (Bindable)model; } /** @@ -76,7 +92,8 @@ public class PathImpl extends AbstractExpression implements Path { * an {@link IllegalStateException} */ public Expression> type() { - throw new IllegalStateException( "type() is not applicable to a primitive path node." ); } + throw new BasicPathUsageException( "type() is not applicable to primitive paths.", getAttribute() ); + } /** * {@inheritDoc} @@ -85,7 +102,11 @@ public class PathImpl extends AbstractExpression implements Path { * an {@link IllegalStateException} */ public Path get(SingularAttribute attribute) { - throw new IllegalStateException( this + " is a primitive path node." ); + throw illegalDereference(); + } + + private BasicPathUsageException illegalDereference() { + return new BasicPathUsageException( "Primitive path cannot be de-referenced", getAttribute() ); } /** @@ -95,7 +116,7 @@ public class PathImpl extends AbstractExpression implements Path { * an {@link IllegalStateException} */ public > Expression get(PluralAttribute collection) { - throw new IllegalStateException( this + " is a primitive path node." ); + throw illegalDereference(); } /** @@ -105,7 +126,7 @@ public class PathImpl extends AbstractExpression implements Path { * an {@link IllegalStateException} */ public > Expression get(MapAttribute map) { - throw new IllegalStateException( this + " is a primitive path node." ); + throw illegalDereference(); } /** @@ -115,7 +136,7 @@ public class PathImpl extends AbstractExpression implements Path { * an {@link IllegalStateException} */ public Path get(String attributeName) { - throw new IllegalStateException( this + " is a primitive path node." ); + throw illegalDereference(); } } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/QueryBuilderImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/QueryBuilderImpl.java index 5c9eedb21d..9b8e42ce6e 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/QueryBuilderImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/QueryBuilderImpl.java @@ -73,7 +73,7 @@ public class QueryBuilderImpl implements QueryBuilder, Serializable { * * @return The underlying {@link EntityManagerFactoryImpl} */ - protected EntityManagerFactoryImpl getEntityManagerFactory() { + public EntityManagerFactoryImpl getEntityManagerFactory() { return entityManagerFactory; } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/RootImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/RootImpl.java index f3fa0b7cce..f425bdaa4c 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/RootImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/RootImpl.java @@ -22,6 +22,7 @@ package org.hibernate.ejb.criteria; import javax.persistence.criteria.Root; +import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.EntityType; /** @@ -41,4 +42,9 @@ public class RootImpl extends FromImpl implements Root { return ( EntityType ) super.getModel(); } + @Override + protected Attribute getAttribute(String name) { + return (Attribute) getModel().getAttribute( name ); + } + } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/SetJoinImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/SetJoinImpl.java new file mode 100644 index 0000000000..dec46bb55a --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/SetJoinImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria; + +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.SetJoin; +import javax.persistence.metamodel.SetAttribute; + +/** + * Represents a join to a persistent collection, defined as type {@link java.util.Set}, whose elements + * are associations. + * + * @author Steve Ebersole + */ +public class SetJoinImpl extends JoinImpl implements SetJoin { + public SetJoinImpl( + QueryBuilderImpl queryBuilder, + Class javaType, + PathImpl lhs, + SetAttribute joinProperty, + JoinType joinType) { + super(queryBuilder, javaType, lhs, joinProperty, joinType); + } + + @Override + public SetAttribute getModel() { + return (SetAttribute) super.getAttribute(); + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/CollectionExpression.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/CollectionExpression.java new file mode 100644 index 0000000000..267a246f85 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/CollectionExpression.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria.expression; + +import javax.persistence.metamodel.PluralAttribute; +import org.hibernate.ejb.criteria.QueryBuilderImpl; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class CollectionExpression extends ExpressionImpl { + private final CollectionPersister persister; + private final PluralAttribute attribute; + + public CollectionExpression( + QueryBuilderImpl queryBuilder, + Class javaType, + PluralAttribute attribute) { + this( queryBuilder, javaType, resolvePersister( queryBuilder, attribute ), attribute ); + } + + private static CollectionPersister resolvePersister(QueryBuilderImpl queryBuilder, PluralAttribute attribute) { + SessionFactoryImplementor sfi = (SessionFactoryImplementor) + queryBuilder.getEntityManagerFactory().getSessionFactory(); + return sfi.getCollectionPersister( resolveRole( attribute ) ); + } + + private static String resolveRole(PluralAttribute attribute) { + return attribute.getDeclaringType().getJavaType().getName() + + '.' + attribute.getName(); + } + + public CollectionExpression( + QueryBuilderImpl queryBuilder, + Class javaType, + CollectionPersister persister, + PluralAttribute attribute) { + super(queryBuilder, javaType); + this.persister = persister; + this.attribute = attribute; + } + + public PluralAttribute getAttribute() { + return attribute; + } + + public CollectionPersister getPersister() { + return persister; + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/EntityTypeExpression.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/EntityTypeExpression.java index 1d08616a8d..2afdd5d1ee 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/EntityTypeExpression.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/EntityTypeExpression.java @@ -28,7 +28,7 @@ import org.hibernate.ejb.criteria.QueryBuilderImpl; * * @author Steve Ebersole */ -public class EntityTypeExpression extends AbstractExpression { +public class EntityTypeExpression extends ExpressionImpl { public EntityTypeExpression(QueryBuilderImpl queryBuilder, Class javaType) { super( queryBuilder, javaType ); } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/AbstractExpression.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ExpressionImpl.java similarity index 92% rename from entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/AbstractExpression.java rename to entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ExpressionImpl.java index be0c77925a..fd9641aee3 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/AbstractExpression.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ExpressionImpl.java @@ -32,8 +32,8 @@ import org.hibernate.ejb.criteria.QueryBuilderImpl; * * @author Steve Ebersole */ -public class AbstractExpression extends SelectionImpl implements Expression { - protected AbstractExpression(QueryBuilderImpl queryBuilder, Class javaType) { +public class ExpressionImpl extends SelectionImpl implements Expression { + public ExpressionImpl(QueryBuilderImpl queryBuilder, Class javaType) { super( queryBuilder, javaType ); } diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/FunctionExpressionImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/FunctionExpressionImpl.java index 55cb56fc21..7d57c32f9a 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/FunctionExpressionImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/FunctionExpressionImpl.java @@ -32,7 +32,7 @@ import org.hibernate.ejb.criteria.QueryBuilderImpl; * * @author Steve Ebersole */ -public class FunctionExpressionImpl extends AbstractExpression implements Expression { +public class FunctionExpressionImpl extends ExpressionImpl implements Expression { private final String functionName; private final List> argumentExpressions; diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ListIndexExpression.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ListIndexExpression.java new file mode 100644 index 0000000000..6fc405715a --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ListIndexExpression.java @@ -0,0 +1,23 @@ +package org.hibernate.ejb.criteria.expression; + +import javax.persistence.metamodel.ListAttribute; +import org.hibernate.ejb.criteria.QueryBuilderImpl; + +/** + * An expression for referring to the index of a list. + * + * @author Steve Ebersole + */ +public class ListIndexExpression extends ExpressionImpl { + private final ListAttribute listAttribute; + + public ListIndexExpression(QueryBuilderImpl queryBuilder, ListAttribute listAttribute) { + super( queryBuilder, Integer.class ); + this.listAttribute = listAttribute; + } + + public ListAttribute getListAttribute() { + return listAttribute; + } + +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java index 89d8264c17..fe33ea8832 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java @@ -28,7 +28,7 @@ import org.hibernate.ejb.criteria.QueryBuilderImpl; * * @author Steve Ebersole */ -public class LiteralExpression extends AbstractExpression { +public class LiteralExpression extends ExpressionImpl { private final T literal; public LiteralExpression( diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java index e0ec349244..3f139f54f2 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java @@ -31,7 +31,7 @@ import org.hibernate.ejb.criteria.QueryBuilderImpl; * * @author Steve Ebersole */ -public class ParameterExpressionImpl extends AbstractExpression implements ParameterExpression { +public class ParameterExpressionImpl extends ExpressionImpl implements ParameterExpression { private final String name; private final Integer position; diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/function/AverageAggregrateFunction.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/function/AverageAggregrateFunction.java new file mode 100644 index 0000000000..9bb982e641 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/function/AverageAggregrateFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria.expression.function; + +import javax.persistence.criteria.Expression; + +import org.hibernate.ejb.criteria.expression.FunctionExpressionImpl; +import org.hibernate.ejb.criteria.QueryBuilderImpl; + +/** + * Implementation of a AVG function providing convenience in construction. + *

+ * Parameterized as {@link Double} because thats what JPA states that the return + * from AVG should be. + * + * @author Steve Ebersole + */ +public class AverageAggregrateFunction extends FunctionExpressionImpl { + public AverageAggregrateFunction( + QueryBuilderImpl queryBuilder, + Expression expression) { + super( queryBuilder, Double.class, "avg", expression ); + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/function/SumAggregateFunction.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/function/SumAggregateFunction.java new file mode 100644 index 0000000000..026ca726d7 --- /dev/null +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/function/SumAggregateFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.ejb.criteria.expression.function; + +import javax.persistence.criteria.Expression; + +import org.hibernate.ejb.criteria.expression.FunctionExpressionImpl; +import org.hibernate.ejb.criteria.QueryBuilderImpl; + +/** + * Implementation of a SUM function providing convenience in construction. + *

+ * Parameterized as {@link Number N extends Number} because thats what JPA states + * that the return from SUM should be. + * + * @author Steve Ebersole + */ +public class SumAggregateFunction extends FunctionExpressionImpl { + public SumAggregateFunction( + QueryBuilderImpl queryBuilder, + Expression expression) { + super( queryBuilder, expression.getJavaType(), "sum", expression ); + } +} diff --git a/entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/AbstractPredicateImpl.java b/entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/AbstractPredicateImpl.java index d6aef31d3b..3ba5320c2e 100644 --- a/entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/AbstractPredicateImpl.java +++ b/entitymanager/src/main/java/org/hibernate/ejb/criteria/predicate/AbstractPredicateImpl.java @@ -25,7 +25,7 @@ import java.util.List; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Selection; -import org.hibernate.ejb.criteria.expression.AbstractExpression; +import org.hibernate.ejb.criteria.expression.ExpressionImpl; import org.hibernate.ejb.criteria.QueryBuilderImpl; /** @@ -34,7 +34,7 @@ import org.hibernate.ejb.criteria.QueryBuilderImpl; * * @author Steve Ebersole */ -public abstract class AbstractPredicateImpl extends AbstractExpression implements Predicate { +public abstract class AbstractPredicateImpl extends ExpressionImpl implements Predicate { private boolean negated; protected AbstractPredicateImpl(QueryBuilderImpl queryBuilder) {