org.batoo.jpa.core.impl.jdbc.CollectionTable.java Source code

Java tutorial

Introduction

Here is the source code for org.batoo.jpa.core.impl.jdbc.CollectionTable.java

Source

/*
 * Copyright (c) 2012 - Batoo Software ve Consultancy Ltd.
 * 
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.batoo.jpa.core.impl.jdbc;

import java.sql.SQLException;
import java.util.Collections;
import java.util.List;

import javax.persistence.EnumType;
import javax.persistence.TemporalType;

import org.batoo.jpa.core.impl.jdbc.dbutils.QueryRunner;
import org.apache.commons.lang.StringUtils;
import org.batoo.jpa.core.impl.model.mapping.ElementMapping;
import org.batoo.jpa.core.impl.model.type.EmbeddableTypeImpl;
import org.batoo.jpa.core.impl.model.type.EntityTypeImpl;
import org.batoo.jpa.core.impl.model.type.TypeImpl;
import org.batoo.jpa.core.jdbc.adapter.JdbcAdaptor;
import org.batoo.jpa.parser.metadata.CollectionTableMetadata;
import org.batoo.jpa.parser.metadata.ColumnMetadata;
import org.batoo.jpa.parser.metadata.JoinColumnMetadata;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

/**
 * The table for element collection attributes.
 * 
 * @author hceylan
 * @since $version
 */
public class CollectionTable extends AbstractTable implements JoinableTable {

    private final JdbcAdaptor jdbcAdaptor;
    private final EntityTypeImpl<?> entity;
    private final ForeignKey key;

    private OrderColumn orderColumn;
    private ElementColumn elementColumn;

    private String removeSql;

    private String removeAllSql;
    private AbstractColumn[] removeColumns;
    private JoinColumn[] removeAllColumns;
    private MapKeyColumn keyColumn;

    /**
     * @param entity
     *            the owner type
     * @param metadata
     *            the metadata
     * 
     * @since $version
     * @author hceylan
     */
    public CollectionTable(EntityTypeImpl<?> entity, CollectionTableMetadata metadata) {
        super(metadata);

        this.entity = entity;
        this.jdbcAdaptor = entity.getMetamodel().getJdbcAdaptor();
        this.key = new ForeignKey(entity.getMetamodel().getJdbcAdaptor(), //
                metadata != null ? metadata.getJoinColumns() : Collections.<JoinColumnMetadata>emptyList());
    }

    /**
     * Returns the key.
     * 
     * @return the key
     * 
     * @since $version
     * @author hceylan
     */
    public ForeignKey getKey() {
        return this.key;
    }

    /**
     * Returns the key column of the collection table.
     * 
     * @return the key column of the collection table
     * 
     * @since $version
     * @author hceylan
     */
    public MapKeyColumn getKeyColumn() {
        return this.keyColumn;
    }

    /**
     * Returns the order column.
     * 
     * @return the order column
     * 
     * @since $version
     * @author hceylan
     */
    public OrderColumn getOrderColumn() {
        return this.orderColumn;
    }

    private String getRemoveAllSql() {
        if (this.removeAllSql != null) {
            return this.removeAllSql;
        }

        synchronized (this) {
            if (this.removeAllSql != null) {
                return this.removeAllSql;
            }

            final List<String> restrictions = Lists.newArrayList();
            this.removeAllColumns = new JoinColumn[this.key.getJoinColumns().size()];

            int i = 0;
            final List<JoinColumn> joinColumns = this.key.getJoinColumns();
            for (int j = 0; j < joinColumns.size(); j++) {
                final JoinColumn column = joinColumns.get(j);
                restrictions.add(column.getName() + " = ?");
                this.removeAllColumns[i++] = column;
            }

            return this.removeAllSql = "DELETE FROM " + this.getQName() + " WHERE "
                    + Joiner.on(" AND ").join(restrictions);
        }
    }

    private String getRemoveSql() {
        if (this.removeSql != null) {
            return this.removeSql;
        }

        synchronized (this) {
            if (this.removeSql != null) {
                return this.removeSql;
            }

            final List<String> restrictions = Lists.newArrayList();
            this.removeColumns = new AbstractColumn[this.getColumns().size()];

            int i = 0;
            for (final AbstractColumn column : this.getColumns()) {
                if (column != this.orderColumn) {
                    restrictions.add(column.getName() + " = ?");
                    this.removeColumns[i++] = column;
                }
            }

            return this.removeSql = "DELETE FROM " + this.getQName() + " WHERE "
                    + Joiner.on(" AND ").join(restrictions);
        }
    }

    /**
     * Links
     * 
     * @param type
     *            the type of the collection
     * @param defaultName
     *            the default name
     * @param elementMapping
     *            the element mapping
     * 
     * @since $version
     * @author hceylan
     */
    public void link(EmbeddableTypeImpl<?> type, String defaultName, ElementMapping<?> elementMapping) {
        if (StringUtils.isBlank(this.getName())) {
            this.setName(defaultName);
        }

        this.key.link(null, this.entity);
        this.key.setTable(this);
    }

    /**
     * @param type
     *            the type of the collection
     * @param defaultName
     *            the default name
     * @param metadata
     *            the column metadata
     * @param lob
     *            if the column is a lob type
     * @param temporalType
     *            the temporal type
     * @param enumType
     *            the enum type
     * 
     * @since $version
     * @author hceylan
     */
    public void link(TypeImpl<?> type, String defaultName, ColumnMetadata metadata, EnumType enumType,
            TemporalType temporalType, boolean lob) {
        if (StringUtils.isBlank(this.getName())) {
            this.setName(this.entity.getName() + "_" + defaultName);
        }

        this.key.link(null, this.entity);
        this.key.setTable(this);

        this.elementColumn = new ElementColumn(this.entity.getMetamodel().getJdbcAdaptor(), //
                this, //
                (metadata == null) || StringUtils.isBlank(metadata.getName()) ? defaultName : metadata.getName(), //
                type.getJavaType(), //
                enumType, //
                temporalType, //
                lob, //
                metadata);
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public void performInsert(ConnectionImpl connection, Object source, Object key, Object destination, int order)
            throws SQLException {
        final String insertSql = this.getInsertSql(null);
        final AbstractColumn[] insertColumns = this.getInsertColumns(null);

        // prepare the parameters
        final Object[] params = new Object[insertColumns.length];
        for (int i = 0; i < insertColumns.length; i++) {
            final AbstractColumn column = insertColumns[i];

            if (column == this.orderColumn) {
                params[i] = order;
            } else if (column == this.keyColumn) {
                params[i] = key;
            } else if (this.elementColumn == column) {
                params[i] = this.elementColumn.getValue(destination);
            } else if (column instanceof JoinColumn) {
                params[i] = column.getValue(source);
            } else {
                params[i] = column.getValue(destination);
            }
        }

        new QueryRunner(this.jdbcAdaptor.isPmdBroken()).update(connection, insertSql, params);
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public void performRemove(ConnectionImpl connection, Object source, Object key, Object destination)
            throws SQLException {
        final String removeSql = this.getRemoveSql();

        final Object[] params = new Object[this.removeColumns.length];

        int i = 0;
        for (final AbstractColumn column : this.removeColumns) {
            if (column instanceof ElementColumn) {
                params[i++] = column.getValue(destination);
            } else if (column == this.keyColumn) {
                params[i++] = key;
            } else if (column instanceof JoinColumn) {
                params[i++] = column.getValue(source);
            } else {
                params[i++] = column.getValue(destination);
            }
        }

        new QueryRunner(this.jdbcAdaptor.isPmdBroken()).update(connection, removeSql, params);
    }

    /**
     * {@inheritDoc}
     * 
     */
    @Override
    public void performRemoveAll(ConnectionImpl connection, Object source) throws SQLException {
        final String removeAllSql = this.getRemoveAllSql();

        final Object[] params = new Object[this.removeAllColumns.length];

        int i = 0;
        for (final JoinColumn sourceRemoveColumn : this.removeAllColumns) {
            params[i++] = sourceRemoveColumn.getValue(source);
        }

        new QueryRunner(this.jdbcAdaptor.isPmdBroken()).update(connection, removeAllSql, params);
    }

    /**
     * Sets the map key column.
     * 
     * @param mapKeyColumn
     *            the map key column definition
     * @param name
     *            the name of the column
     * @param mapKeyTemporalType
     *            the temporal type of the map key
     * @param mapKeyEnumType
     *            the enum type of the map key
     * @param mapKeyJavaType
     *            the java type of the map's key
     * 
     * @since $version
     * @author hceylan
     */
    public void setKeyColumn(ColumnMetadata mapKeyColumn, String name, TemporalType mapKeyTemporalType,
            EnumType mapKeyEnumType, Class<?> mapKeyJavaType) {
        this.keyColumn = new MapKeyColumn(this, mapKeyColumn, name, mapKeyTemporalType, mapKeyEnumType,
                mapKeyJavaType);
    }

    /**
     * Sets the order column for the owned list type joins
     * 
     * @param orderColumn
     *            the order column definition
     * @param name
     *            the name of the column
     * 
     * @since $version
     * @author hceylan
     */
    public void setOrderColumn(ColumnMetadata orderColumn, String name) {
        this.orderColumn = new OrderColumn(this, orderColumn, name);
    }
}