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

com.quinsoft.zeidon.dbhandler.StandardJdbcTranslator Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/**
    This file is part of the Zeidon Java Object Engine (Zeidon JOE).

    Zeidon JOE is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zeidon JOE 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 Zeidon JOE.  If not, see .

    Copyright 2009-2015 QuinSoft
 */

package com.quinsoft.zeidon.dbhandler;

import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;

import com.quinsoft.zeidon.GeneratedKey;
import com.quinsoft.zeidon.Task;
import com.quinsoft.zeidon.View;
import com.quinsoft.zeidon.ZeidonException;
import com.quinsoft.zeidon.dbhandler.AbstractSqlHandler.SqlStatement;
import com.quinsoft.zeidon.domains.AbstractNumericDomain;
import com.quinsoft.zeidon.domains.BlobDomain;
import com.quinsoft.zeidon.domains.BooleanDomain;
import com.quinsoft.zeidon.domains.DateDomain;
import com.quinsoft.zeidon.domains.DateTimeDomain;
import com.quinsoft.zeidon.domains.Domain;
import com.quinsoft.zeidon.domains.GeneratedKeyDomain;
import com.quinsoft.zeidon.objectdefinition.AttributeDef;
import com.quinsoft.zeidon.objectdefinition.DataField;

/**
 * The standard JDBC domain translator.
 *
 * @author DG
 *
 */
public class StandardJdbcTranslator implements JdbcDomainTranslator
{
    protected static final int MAX_INLINE_STRING_LENGTH = 100;

    /**
     * Thread-safe formatter for converting to string.
     **/
    protected final DateTimeFormatter dateFormatter;
    protected final DateTimeFormatter dateTimeFormatter;

    private final Task        task;

    /**
     * If true, then we'll use '?' for all attribute values when building the SQL.
     * This protects a task from possible SQL injection.
     */
    final boolean bindAllValues;

    public StandardJdbcTranslator(Task task, JdbcHandler handler )
    {
        super();
        this.task = task;
        bindAllValues = handler.isBindAllValues();
        dateFormatter = handler.getDateFormatter();
        dateTimeFormatter = handler.getDateTimeFormatter();
    }

    protected Task getTask()
    {
        return task;
    }

    protected boolean appendString( SqlStatement stmt, StringBuilder buffer, Object value )
    {
        String str = value.toString();
        if ( str.length() > MAX_INLINE_STRING_LENGTH || bindAllValues)
        {
            if ( getTask().dblog().isTraceEnabled() )
                getTask().dblog().trace( "Bound string: length = %d, value = %s...", str.length(), StringUtils.substring( str, 0, 50 ) );

            stmt.addBoundAttribute( buffer, value );
        }
        else
        {
            buffer.append( "'" ).append( StringUtils.replace( str, "'", "''" ) ).append( "'" );
        }

        return true;
    }

    protected boolean appendNumeric(SqlStatement stmt, StringBuilder buffer, Object value )
    {
        if ( bindAllValues )
            stmt.addBoundAttribute( buffer, value );
        else
            buffer.append( value.toString() );

        return true;
    }

    /* (non-Javadoc)
     * @see com.quinsoft.zeidon.dbhandler.JdbcDomainTranslator#getAttributeValue(java.lang.StringBuilder, com.quinsoft.zeidon.objectdefinition.DataField, com.quinsoft.zeidon.EntityInstance)
     */
    @Override
    public boolean appendSqlValue(SqlStatement stmt, StringBuilder buffer, Domain domain, AttributeDef attributeDef, Object value)
    {
        if ( bindAllValues )
        {
            Object dbValue = domain.convertValueForDb( task, attributeDef, value );
            stmt.addBoundAttribute( buffer, dbValue );
            return true;
        }

        if ( value == null )
        {
            buffer.append( "null" );
            return true;
        }

        if ( domain instanceof GeneratedKeyDomain )
        {
            // The default for DBs is that the key is an integer so copy the value of the
            // attribute directly to the buffer (i.e. without quotes).
            buffer.append( ((GeneratedKey) value).getString() );
            return true;
        }

        if ( domain instanceof DateTimeDomain )
        {
            // Convert the value (likely a string) to a date.
            Object v = domain.convertExternalValue( task, null, attributeDef, null, value );
            String str = dateTimeFormatter.print( (DateTime) v );
            return appendString( stmt, buffer, str );
        }

        if ( domain instanceof DateDomain )
        {
            // Convert the value (likely a string) to a date.
            Object v = domain.convertExternalValue( task, null, attributeDef, null, value );
            String str = dateFormatter.print( (DateTime) v );
            return appendString( stmt, buffer, str );
        }

        if ( domain instanceof AbstractNumericDomain )
        {
            return appendNumeric( stmt, buffer, value );
        }

        if ( domain instanceof BooleanDomain )
        {
            Object b = domain.convertExternalValue( task, null, attributeDef, null, value );
            buffer.append( (Boolean) b ? "true" : "false" );
            return true;
        }

        if ( domain instanceof BlobDomain )
        {
            String s = domain.convertToString( task, attributeDef, value );
            return appendString( stmt, buffer, s );
        }

//        String string = domain.convertToString( task, attributeDef, value );
        return appendString( stmt, buffer, value.toString() );
    }

    /**
     * Takes a value loaded from the DB and potentially converts it.
     */
    @Override
    public Object convertDbValue(Domain domain, Object dbValue) throws SQLException
    {
        if ( dbValue instanceof Clob )
        {
            Clob clob = (Clob) dbValue;
            return clob.getSubString( 1L, (int) clob.length() );
        }

        if ( domain instanceof DateDomain )
        {
            if ( dbValue instanceof CharSequence )
            {
                String date = dbValue.toString();
                try
                {
                    return this.dateFormatter.parseDateTime( date );
                }
                catch ( IllegalArgumentException e )
                {
                    throw ZeidonException.prependMessage( e, "Invalid date format.  Got '%s' but expected format '%s'",
                                                          date, dateFormatter );
                }
            }
            else
            if ( dbValue instanceof Date )
            {
                return new DateTime( dbValue );
            }
        }

        if ( domain instanceof DateTimeDomain )
        {
            if ( dbValue instanceof CharSequence )
            {
                String date = dbValue.toString();
                try
                {
                    return dateTimeFormatter.parseDateTime( date );
                }
                catch ( IllegalArgumentException e )
                {
                    throw ZeidonException.prependMessage( e, "Invalid datetime format.  Got '%s' but expected format '%s'",
                                                          date, dateTimeFormatter );
                }
            }
        }

        return dbValue;
    }

    /* (non-Javadoc)
     * @see com.quinsoft.zeidon.dbhandler.JdbcDomainTranslator#bindAttributeValue(java.sql.PreparedStatement, com.quinsoft.zeidon.View, com.quinsoft.zeidon.objectdefinition.DataField, int)
     */
    @Override
    public String bindAttributeValue( PreparedStatement ps, View view, DataField dataField, int idx )
    {
        final AttributeDef attributeDef = dataField.getAttributeDef();
        Domain domain = attributeDef.getDomain();
        Object value;
        if ( domain instanceof BlobDomain )
        	value = view.cursor( attributeDef.getEntityDef() ).getAttribute( attributeDef ).getString();
        else
        {
        	value = view.cursor( attributeDef.getEntityDef() ).getAttribute( attributeDef ).getValue();
        	value = domain.convertValueForDb( getTask(), attributeDef, value );
        }

        value = AbstractSqlHandler.convertEmptyStringValue( value, attributeDef );

        try
        {
            return bindAttributeValue( ps, value, idx );
        }
        catch ( Exception e )
        {
            throw ZeidonException.wrapException( e ).prependAttributeDef( attributeDef );
        }
    }

    @Override
    public String bindAttributeValue( PreparedStatement ps, Object value, int idx )
    {
        try
        {
            if ( value instanceof DateTime )
            {
                DateTime d = (DateTime) value;
                ps.setTimestamp( idx, new java.sql.Timestamp( d.getMillis() ) );
            }
            else
            if ( value instanceof GeneratedKey )
            {
                GeneratedKey k = (GeneratedKey) value;
                ps.setObject( idx, k.getNativeValue() );
            }
            else
            {
                ps.setObject( idx, value );
            }

            if ( value == null )
                return "";

            return value.toString();
        }
        catch ( Exception e )
        {
            String className = value == null ? "" : value.getClass().getCanonicalName();
            throw ZeidonException.wrapException( e ).appendMessage( "Col index: %d\nValue %s\nClass: %s", idx, value, className );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy