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

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

The 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 com.quinsoft.zeidon.Blob;
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.DomainDateTimeFormatter;
import com.quinsoft.zeidon.domains.GeneratedKeyDomain;
import com.quinsoft.zeidon.objectdefinition.AttributeDef;
import com.quinsoft.zeidon.objectdefinition.DataField;
import org.apache.commons.lang3.StringUtils;

import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.UUID;

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

    /**
     * Thread-safe formatter for converting to string.
     **/
    protected final DomainDateTimeFormatter dateFormatter;
    protected final DomainDateTimeFormatter 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, AttributeDef attributeDef, 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 ) );

            DataField dataField = attributeDef.getEntityDef().getDataRecord().getDataField( attributeDef );
            stmt.addBoundAttribute( buffer, new BoundAttributeData( dataField, value ) );

            //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 );
            DataField dataField = attributeDef.getEntityDef().getDataRecord().getDataField( attributeDef );
            stmt.addBoundAttribute( buffer, new BoundAttributeData( dataField, 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.format( (ZonedDateTime) v );
            return appendString( stmt, buffer, attributeDef, 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.format( (ZonedDateTime) v );
            return appendString( stmt, buffer, attributeDef, 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, attributeDef, s );
        }

//        String string = domain.convertToString( task, attributeDef, value );
        return appendString( stmt, buffer, attributeDef, 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();
                return dateTimeFormatter.parse( date );
            }
            else
            if ( dbValue instanceof java.sql.Date )
            {
                return ( (java.sql.Date) dbValue).toLocalDate().atStartOfDay( ZoneId.systemDefault() ) ;
            }
            else
            if ( dbValue instanceof java.util.Date )
            {
                return ZonedDateTime.ofInstant( ( (java.util.Date) dbValue).toInstant(),
                                                ZoneId.systemDefault() );
            }
        }

        if ( domain instanceof DateTimeDomain )
        {
            if ( dbValue instanceof CharSequence )
            {
                String date = dbValue.toString();
                ZonedDateTime dt = dateTimeFormatter.parse( date );
                return dt;
            }
        }

        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 ).getBlob();
            try
            {
                if ( value == null )
                {
                    ps.setObject( idx, value, Types.LONGVARBINARY, -1 );
                    return "";
                }
            }
            catch ( SQLException e )
            {
                throw ZeidonException.wrapException( e ).prependAttributeDef( attributeDef );
            }
        }
        else
        {
        	value = view.cursor( attributeDef.getEntityDef() ).getAttribute( attributeDef ).getValue();
        	value = domain.convertValueForDb( getTask(), attributeDef, value );
        }

        value = AbstractSqlHandler.convertEmptyStringValue( value, attributeDef );

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

    @Override
    public String bindAttributeValue( PreparedStatement ps, BoundAttributeData data, int idx )
    {
        if ( data.value instanceof Collection )
            return bindCollectionValue( ps, data, idx );

        final AttributeDef attributeDef = data.dataField.getAttributeDef();
        Domain domain = attributeDef.getDomain();
        Object value = data.value;
        try
        {
            if ( domain instanceof BlobDomain )
            {
                if ( value == null )
                {
                    ps.setObject( idx, value, Types.LONGVARBINARY, -1 );
                    return "";
                }
                Blob blob = (Blob) value;
                ps.setObject( idx, blob.getBytes() ); // If blob is varbinary
            }
            else if ( value instanceof ZonedDateTime )
            {
                ZonedDateTime d = (ZonedDateTime) value;
                java.sql.Timestamp timestamp = java.sql.Timestamp.valueOf( d.toLocalDateTime() );
                ps.setTimestamp( idx, timestamp );
            }
            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 );
        }
    }

    protected String getArrayType( DataField dataField, Collection collection )
    {
        Object value = collection.iterator().next();

        if ( value instanceof Integer )
            return "int";

        if ( value instanceof UUID )
            return "UUID";

        return "text";
    }

    protected String bindCollectionValue( PreparedStatement ps, BoundAttributeData data, int idx )
    {
        Collection collection = (Collection) data.value;
        try
        {
            Object[] array = collection.toArray( new Object[ collection.size() ] );
            String arrayType = getArrayType( data.dataField, collection );
            ps.setArray( idx, ps.getConnection().createArrayOf( arrayType, array ) );
            return collection.toString();
        }
        catch ( SQLException e )
        {
            throw ZeidonException.wrapException( e );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy