com.quinsoft.zeidon.dbhandler.StandardJdbcTranslator.java Source code

Java tutorial

Introduction

Here is the source code for com.quinsoft.zeidon.dbhandler.StandardJdbcTranslator.java

Source

/**
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 <http://www.gnu.org/licenses/>.
    
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) {
            stmt.addBoundAttribute(buffer, value);
            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();
        final Object value = view.cursor(attributeDef.getEntityDef()).getAttribute(attributeDef).getValue();

        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.setObject(idx, new Date(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 "<null>";

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