org.hibernate.dialect.function.AbstractAnsiTrimEmulationFunction.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.dialect.function.AbstractAnsiTrimEmulationFunction.java

Source

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.dialect.function;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.QueryException;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;

/**
 * A {@link org.hibernate.dialect.function.SQLFunction} providing support for implementing TRIM functionality
 * (as defined by both the ANSI SQL and JPA specs) in cases where the dialect may not support the full <tt>trim</tt>
 * function itself.
 * <p/>
 * Follows the <a href="http://en.wikipedia.org/wiki/Template_method_pattern">template</a> pattern in order to implement
 * the {@link #render} method.
 *
 * @author Steve Ebersole
 */
public abstract class AbstractAnsiTrimEmulationFunction implements SQLFunction {
    @Override
    public final boolean hasArguments() {
        return true;
    }

    @Override
    public final boolean hasParenthesesIfNoArguments() {
        return false;
    }

    @Override
    public final Type getReturnType(Type argumentType, Mapping mapping) throws QueryException {
        return StandardBasicTypes.STRING;
    }

    @Override
    public final String render(Type argumentType, List args, SessionFactoryImplementor factory)
            throws QueryException {
        // According to both the ANSI-SQL and JPA specs, trim takes a variable number of parameters between 1 and 4.
        // at least one paramer (trimSource) is required.  From the SQL spec:
        //
        // <trim function> ::=
        //      TRIM <left paren> <trim operands> <right paren>
        //
        // <trim operands> ::=
        //      [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
        //
        // <trim specification> ::=
        //      LEADING
        //      | TRAILING
        //      | BOTH
        //
        // If <trim specification> is omitted, BOTH is assumed.
        // If <trim character> is omitted, space is assumed
        if (args.size() == 1) {
            // we have the form: trim(trimSource)
            //      so we trim leading and trailing spaces
            return resolveBothSpaceTrimFunction().render(argumentType, args, factory);
        } else if ("from".equalsIgnoreCase((String) args.get(0))) {
            // we have the form: trim(from trimSource).
            //      This is functionally equivalent to trim(trimSource)
            return resolveBothSpaceTrimFromFunction().render(argumentType, args, factory);
        } else {
            // otherwise, a trim-specification and/or a trim-character
            // have been specified;  we need to decide which options
            // are present and "do the right thing"

            // should leading trim-characters be trimmed?
            boolean leading = true;
            // should trailing trim-characters be trimmed?
            boolean trailing = true;
            // the trim-character (what is to be trimmed off?)
            String trimCharacter;
            // the trim-source (from where should it be trimmed?)
            String trimSource;

            // potentialTrimCharacterArgIndex = 1 assumes that a
            // trim-specification has been specified.  we handle the
            // exception to that explicitly
            int potentialTrimCharacterArgIndex = 1;
            final String firstArg = (String) args.get(0);
            if ("leading".equalsIgnoreCase(firstArg)) {
                trailing = false;
            } else if ("trailing".equalsIgnoreCase(firstArg)) {
                leading = false;
            } else if ("both".equalsIgnoreCase(firstArg)) {
                // nothing to do here
            } else {
                potentialTrimCharacterArgIndex = 0;
            }

            final String potentialTrimCharacter = (String) args.get(potentialTrimCharacterArgIndex);
            if ("from".equalsIgnoreCase(potentialTrimCharacter)) {
                trimCharacter = "' '";
                trimSource = (String) args.get(potentialTrimCharacterArgIndex + 1);
            } else if (potentialTrimCharacterArgIndex + 1 >= args.size()) {
                trimCharacter = "' '";
                trimSource = potentialTrimCharacter;
            } else {
                trimCharacter = potentialTrimCharacter;
                if ("from".equalsIgnoreCase((String) args.get(potentialTrimCharacterArgIndex + 1))) {
                    trimSource = (String) args.get(potentialTrimCharacterArgIndex + 2);
                } else {
                    trimSource = (String) args.get(potentialTrimCharacterArgIndex + 1);
                }
            }

            final List<String> argsToUse = new ArrayList<String>();
            argsToUse.add(trimSource);
            argsToUse.add(trimCharacter);

            if (trimCharacter.equals("' '")) {
                if (leading && trailing) {
                    return resolveBothSpaceTrimFunction().render(argumentType, argsToUse, factory);
                } else if (leading) {
                    return resolveLeadingSpaceTrimFunction().render(argumentType, argsToUse, factory);
                } else {
                    return resolveTrailingSpaceTrimFunction().render(argumentType, argsToUse, factory);
                }
            } else {
                if (leading && trailing) {
                    return resolveBothTrimFunction().render(argumentType, argsToUse, factory);
                } else if (leading) {
                    return resolveLeadingTrimFunction().render(argumentType, argsToUse, factory);
                } else {
                    return resolveTrailingTrimFunction().render(argumentType, argsToUse, factory);
                }
            }
        }
    }

    /**
     * Resolve the function definition which should be used to trim both leading and trailing spaces.
     * <p/>
     * In this form, the imput arguments is missing the <tt>FROM</tt> keyword.
     *
     * @return The sql function
     */
    protected abstract SQLFunction resolveBothSpaceTrimFunction();

    /**
     * Resolve the function definition which should be used to trim both leading and trailing spaces.
     * <p/>
     * The same as {#link resolveBothSpaceTrimFunction} except that here the<tt>FROM</tt> is included and
     * will need to be accounted for during {@link SQLFunction#render} processing.
     * 
     * @return The sql function
     */
    protected abstract SQLFunction resolveBothSpaceTrimFromFunction();

    /**
     * Resolve the function definition which should be used to trim leading spaces.
     *
     * @return The sql function
     */
    protected abstract SQLFunction resolveLeadingSpaceTrimFunction();

    /**
     * Resolve the function definition which should be used to trim trailing spaces.
     *
     * @return The sql function
     */
    protected abstract SQLFunction resolveTrailingSpaceTrimFunction();

    /**
     * Resolve the function definition which should be used to trim the specified character from both the
     * beginning (leading) and end (trailing) of the trim source.
     *
     * @return The sql function
     */
    protected abstract SQLFunction resolveBothTrimFunction();

    /**
     * Resolve the function definition which should be used to trim the specified character from the
     * beginning (leading) of the trim source.
     *
     * @return The sql function
     */
    protected abstract SQLFunction resolveLeadingTrimFunction();

    /**
     * Resolve the function definition which should be used to trim the specified character from the
     * end (trailing) of the trim source.
     *
     * @return The sql function
     */
    protected abstract SQLFunction resolveTrailingTrimFunction();
}