All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.metamodel.source.annotations.global.QueryBinder Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2011, Red Hat Inc. 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 Inc.
 *
 * 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.metamodel.source.annotations.global;

import java.util.HashMap;
import java.util.List;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.logging.Logger;

import org.hibernate.AnnotationException;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.LockMode;
import org.hibernate.annotations.QueryHints;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.metamodel.source.annotations.JandexHelper;

/**
 * Binds {@link NamedQuery}, {@link NamedQueries}, {@link NamedNativeQuery}, {@link NamedNativeQueries},
 * {@link org.hibernate.annotations.NamedQuery}, {@link org.hibernate.annotations.NamedQueries},
 * {@link org.hibernate.annotations.NamedNativeQuery}, and {@link org.hibernate.annotations.NamedNativeQueries}.
 *
 * @author Hardy Ferentschik
 */
public class QueryBinder {

	private static final CoreMessageLogger LOG = Logger.getMessageLogger(
			CoreMessageLogger.class,
			QueryBinder.class.getName()
	);

	private QueryBinder() {
	}

	/**
	 * Binds all {@link NamedQuery}, {@link NamedQueries}, {@link NamedNativeQuery}, {@link NamedNativeQueries},
	 * {@link org.hibernate.annotations.NamedQuery}, {@link org.hibernate.annotations.NamedQueries},
	 * {@link org.hibernate.annotations.NamedNativeQuery}, and {@link org.hibernate.annotations.NamedNativeQueries}
	 * annotations to the supplied metadata.
	 *
	 * @param bindingContext the context for annotation binding
	 */
	public static void bind(AnnotationBindingContext bindingContext) {
		List annotations = bindingContext.getIndex().getAnnotations( JPADotNames.NAMED_QUERY );
		for ( AnnotationInstance query : annotations ) {
			bindNamedQuery( bindingContext.getMetadataImplementor(), query );
		}

		annotations = bindingContext.getIndex().getAnnotations( JPADotNames.NAMED_QUERIES );
		for ( AnnotationInstance queries : annotations ) {
			for ( AnnotationInstance query : JandexHelper.getValue( queries, "value", AnnotationInstance[].class ) ) {
				bindNamedQuery( bindingContext.getMetadataImplementor(), query );
			}
		}

		annotations = bindingContext.getIndex().getAnnotations( JPADotNames.NAMED_NATIVE_QUERY );
		for ( AnnotationInstance query : annotations ) {
			bindNamedNativeQuery( bindingContext.getMetadataImplementor(), query );
		}

		annotations = bindingContext.getIndex().getAnnotations( JPADotNames.NAMED_NATIVE_QUERIES );
		for ( AnnotationInstance queries : annotations ) {
			for ( AnnotationInstance query : JandexHelper.getValue( queries, "value", AnnotationInstance[].class ) ) {
				bindNamedNativeQuery( bindingContext.getMetadataImplementor(), query );
			}
		}

		annotations = bindingContext.getIndex().getAnnotations( HibernateDotNames.NAMED_QUERY );
		for ( AnnotationInstance query : annotations ) {
			bindNamedQuery( bindingContext.getMetadataImplementor(), query );
		}

		annotations = bindingContext.getIndex().getAnnotations( HibernateDotNames.NAMED_QUERIES );
		for ( AnnotationInstance queries : annotations ) {
			for ( AnnotationInstance query : JandexHelper.getValue( queries, "value", AnnotationInstance[].class ) ) {
				bindNamedQuery( bindingContext.getMetadataImplementor(), query );
			}
		}

		annotations = bindingContext.getIndex().getAnnotations( HibernateDotNames.NAMED_NATIVE_QUERY );
		for ( AnnotationInstance query : annotations ) {
			bindNamedNativeQuery( bindingContext.getMetadataImplementor(), query );
		}

		annotations = bindingContext.getIndex().getAnnotations( HibernateDotNames.NAMED_NATIVE_QUERIES );
		for ( AnnotationInstance queries : annotations ) {
			for ( AnnotationInstance query : JandexHelper.getValue( queries, "value", AnnotationInstance[].class ) ) {
				bindNamedNativeQuery( bindingContext.getMetadataImplementor(), query );
			}
		}
	}

	/**
	 * Binds {@link javax.persistence.NamedQuery} as well as {@link org.hibernate.annotations.NamedQuery}.
	 *
	 * @param metadata the current metadata
	 * @param annotation the named query annotation
	 */
	private static void bindNamedQuery(MetadataImplementor metadata, AnnotationInstance annotation) {
		String name = JandexHelper.getValue( annotation, "name", String.class );
		if ( StringHelper.isEmpty( name ) ) {
			throw new AnnotationException( "A named query must have a name when used in class or package level" );
		}

		String query = JandexHelper.getValue( annotation, "query", String.class );

		AnnotationInstance[] hints = JandexHelper.getValue( annotation, "hints", AnnotationInstance[].class );

		String cacheRegion = getString( hints, QueryHints.CACHE_REGION );
		if ( StringHelper.isEmpty( cacheRegion ) ) {
			cacheRegion = null;
		}

		Integer timeout = getTimeout( hints, query );
		if ( timeout != null && timeout < 0 ) {
			timeout = null;
		}

		Integer fetchSize = getInteger( hints, QueryHints.FETCH_SIZE, name );
		if ( fetchSize != null && fetchSize < 0 ) {
			fetchSize = null;
		}

		String comment = getString( hints, QueryHints.COMMENT );
		if ( StringHelper.isEmpty( comment ) ) {
			comment = null;
		}

		metadata.addNamedQuery(
				new NamedQueryDefinition(
						name,
						query, getBoolean( hints, QueryHints.CACHEABLE, name ), cacheRegion,
						timeout, fetchSize, getFlushMode( hints, QueryHints.FLUSH_MODE, name ),
						getCacheMode( hints, QueryHints.CACHE_MODE, name ),
						getBoolean( hints, QueryHints.READ_ONLY, name ), comment, null
				)
		);
		LOG.debugf( "Binding named query: %s => %s", name, query );
	}

	private static void bindNamedNativeQuery(MetadataImplementor metadata, AnnotationInstance annotation) {
		String name = JandexHelper.getValue( annotation, "name", String.class );
		if ( StringHelper.isEmpty( name ) ) {
			throw new AnnotationException( "A named native query must have a name when used in class or package level" );
		}

		String query = JandexHelper.getValue( annotation, "query", String.class );

		String resultSetMapping = JandexHelper.getValue( annotation, "resultSetMapping", String.class );

		AnnotationInstance[] hints = JandexHelper.getValue( annotation, "hints", AnnotationInstance[].class );

		boolean cacheable = getBoolean( hints, "org.hibernate.cacheable", name );
		String cacheRegion = getString( hints, QueryHints.CACHE_REGION );
		if ( StringHelper.isEmpty( cacheRegion ) ) {
			cacheRegion = null;
		}

		Integer timeout = getTimeout( hints, query );
		if ( timeout != null && timeout < 0 ) {
			timeout = null;
		}

		Integer fetchSize = getInteger( hints, QueryHints.FETCH_SIZE, name );
		if ( fetchSize != null && fetchSize < 0 ) {
			fetchSize = null;
		}

		FlushMode flushMode = getFlushMode( hints, QueryHints.FLUSH_MODE, name );
		CacheMode cacheMode = getCacheMode( hints, QueryHints.CACHE_MODE, name );

		boolean readOnly = getBoolean( hints, QueryHints.READ_ONLY, name );

		String comment = getString( hints, QueryHints.COMMENT );
		if ( StringHelper.isEmpty( comment ) ) {
			comment = null;
		}

		boolean callable = getBoolean( hints, QueryHints.CALLABLE, name );
		NamedSQLQueryDefinition def;
		if ( StringHelper.isNotEmpty( resultSetMapping ) ) {
			def = new NamedSQLQueryDefinition(
					name,
					query, resultSetMapping, null, cacheable,
					cacheRegion, timeout, fetchSize,
					flushMode, cacheMode, readOnly, comment,
					null, callable
			);
		}
		else {
			AnnotationValue annotationValue = annotation.value( "resultClass" );
			if ( annotationValue == null ) {
				throw new NotYetImplementedException( "Pure native scalar queries are not yet supported" );
			}
			NativeSQLQueryRootReturn queryRoots[] = new NativeSQLQueryRootReturn[] {
					new NativeSQLQueryRootReturn(
							"alias1",
							annotationValue.asString(),
							new HashMap(),
							LockMode.READ
					)
			};
			def = new NamedSQLQueryDefinition(
					name,
					query,
					queryRoots,
					null,
					cacheable,
					cacheRegion,
					timeout,
					fetchSize,
					flushMode,
					cacheMode,
					readOnly,
					comment,
					null,
					callable
			);
		}
		metadata.addNamedNativeQuery( def );
		LOG.debugf( "Binding named native query: %s => %s", name, query );
	}

	private static boolean getBoolean(AnnotationInstance[] hints, String element, String query) {
		String val = getString( hints, element );
		if ( val == null || val.equalsIgnoreCase( "false" ) ) {
			return false;
		}
		if ( val.equalsIgnoreCase( "true" ) ) {
			return true;
		}
		throw new AnnotationException( "Not a boolean in hint: " + query + ":" + element );
	}

	private static CacheMode getCacheMode(AnnotationInstance[] hints, String element, String query) {
		String val = getString( hints, element );
		if ( val == null ) {
			return null;
		}
		if ( val.equalsIgnoreCase( CacheMode.GET.toString() ) ) {
			return CacheMode.GET;
		}
		if ( val.equalsIgnoreCase( CacheMode.IGNORE.toString() ) ) {
			return CacheMode.IGNORE;
		}
		if ( val.equalsIgnoreCase( CacheMode.NORMAL.toString() ) ) {
			return CacheMode.NORMAL;
		}
		if ( val.equalsIgnoreCase( CacheMode.PUT.toString() ) ) {
			return CacheMode.PUT;
		}
		if ( val.equalsIgnoreCase( CacheMode.REFRESH.toString() ) ) {
			return CacheMode.REFRESH;
		}
		throw new AnnotationException( "Unknown CacheMode in hint: " + query + ":" + element );
	}

	private static FlushMode getFlushMode(AnnotationInstance[] hints, String element, String query) {
		String val = getString( hints, element );
		if ( val == null ) {
			return null;
		}
		if ( val.equalsIgnoreCase( FlushMode.ALWAYS.toString() ) ) {
			return FlushMode.ALWAYS;
		}
		else if ( val.equalsIgnoreCase( FlushMode.AUTO.toString() ) ) {
			return FlushMode.AUTO;
		}
		else if ( val.equalsIgnoreCase( FlushMode.COMMIT.toString() ) ) {
			return FlushMode.COMMIT;
		}
		else if ( val.equalsIgnoreCase( FlushMode.NEVER.toString() ) ) {
			return FlushMode.MANUAL;
		}
		else if ( val.equalsIgnoreCase( FlushMode.MANUAL.toString() ) ) {
			return FlushMode.MANUAL;
		}
		else {
			throw new AnnotationException( "Unknown FlushMode in hint: " + query + ":" + element );
		}
	}

	private static Integer getInteger(AnnotationInstance[] hints, String element, String query) {
		String val = getString( hints, element );
		if ( val == null ) {
			return null;
		}
		try {
			return Integer.decode( val );
		}
		catch ( NumberFormatException nfe ) {
			throw new AnnotationException( "Not an integer in hint: " + query + ":" + element, nfe );
		}
	}

	private static String getString(AnnotationInstance[] hints, String element) {
		for ( AnnotationInstance hint : hints ) {
			if ( element.equals( JandexHelper.getValue( hint, "name", String.class ) ) ) {
				return JandexHelper.getValue( hint, "value", String.class );
			}
		}
		return null;
	}

	private static Integer getTimeout(AnnotationInstance[] hints, String query) {
		Integer timeout = getInteger( hints, QueryHints.TIMEOUT_JPA, query );
		if ( timeout == null ) {
			return getInteger( hints, QueryHints.TIMEOUT_HIBERNATE, query ); // timeout is already in seconds
		}
		return ( ( timeout + 500 ) / 1000 ); // convert milliseconds to seconds (rounded)
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy