Java tutorial
/* * 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(); }