alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (UpdateQueryPlan.java)

This example Glassfish source code file (UpdateQueryPlan.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

act_insert, act_insert, act_update, arraylist, arraylist, columnelement, columnelement, iterator, localfielddesc, object, querytable, statement, updatestatement, updatestatement, util

The Glassfish UpdateQueryPlan.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * UpdateQueryPlan.java
 *
 * Created on October 3, 2001
 *
 */

package com.sun.jdo.spi.persistence.support.sqlstore.sql.generator;

import org.netbeans.modules.dbschema.ColumnElement;
import org.netbeans.modules.dbschema.TableElement;
import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager;
import com.sun.jdo.spi.persistence.support.sqlstore.Transaction;
import com.sun.jdo.spi.persistence.support.sqlstore.model.*;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateJoinTableDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl;
import org.glassfish.persistence.common.I18NHelper;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;


/**
 * This class is used to generated update/insert/delete statements.
 */
public class UpdateQueryPlan extends QueryPlan {

    /** Flag indicating whether we use batch update. */
    private boolean batch = false;

    private UpdateObjectDescImpl updateDesc;

    public UpdateQueryPlan(ActionDesc desc, SQLStoreManager store) {
        super(desc, store);
        this.updateDesc = (UpdateObjectDescImpl) desc;
        this.action = getAction(updateDesc.getUpdateAction());
    }

    private static int getAction(int updateAction) {
        if (updateAction == ActionDesc.LOG_CREATE) {
            return ACT_INSERT;
        } else if (updateAction == ActionDesc.LOG_DESTROY) {
            return ACT_DELETE;
        } else if (updateAction == ActionDesc.LOG_UPDATE) {
            return ACT_UPDATE;
        } else {
            return ACT_NOOP;
        }
    }

    /**
     * Specifies an field the data for which needs to be updated,
     * and the mapped columns for which therefor need to be updated.
     * For update queries the column will be put in the set lists,
     * and for insert queries the column will be put into the
     * insert values lists.
     *
     * @param fieldDesc Updated field corresponding to a column in the database.
     * @param value New value.
     */
    private void addColumn(LocalFieldDesc fieldDesc, Object value) {

        // Ignore secondary tracked fields.
        if ((fieldDesc.sqlProperties & FieldDesc.PROP_SECONDARY_TRACKED_FIELD) > 0) {
            return;
        }

        for (Iterator iter = fieldDesc.getColumnElements(); iter.hasNext(); ) {
            ColumnElement columnElement = (ColumnElement) iter.next();
            TableElement tableElement = columnElement.getDeclaringTable();

            if (tableElement == null) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.configuration.fieldnotable", // NOI18N
                        fieldDesc.getName()));
            }

            QueryTable t = findQueryTable(tableElement);
            UpdateStatement s = null;

            if (t == null) {
                t = addQueryTable(tableElement, null);
                s = (UpdateStatement) addStatement(t);
            } else {
                s = (UpdateStatement) getStatement(t);
            }

            if (fieldDesc.isVersion() && action == ACT_UPDATE) {
                // For update, version columns will be flagged specially.
                s.addVersionColumn(columnElement);
            } else {
                s.addColumn(columnElement, value);
            }

        }
    }

    public void build() {
        build(false);
    }

    /**
     * Builds a UpdateQueryPlan for an object based update
     * type (i.e. insert, update, delete) ActionDesc.
     *
     * @param batch Flag indicating whether we use batch update.
     */
    public void build(boolean batch) {

        if ((status & ST_BUILT) > 0) return;

        this.batch = batch;

        generateStatements();

        addColumns();

        if (statements.size() > 0) {
            processStatements();
        }

        processJoinTables();

        status = status | ST_BUILT;
    }

    private void generateStatements() {
        // For insert and delete we build a statement for each table
        if ((action == ACT_DELETE) || (action == ACT_INSERT)) {
            Iterator iter = config.getTables();
            while (iter.hasNext()) {
                TableDesc t = (TableDesc) iter.next();

                // Skip join tables
                if (!t.isJoinTable()) {
                    if (findQueryTable(t.getTableElement()) == null)
                        addStatement(addQueryTable(t));
                }
            }

            // For insert statements, we need to reverse the order.
            if (action == ACT_INSERT) {
                int i = 0;
                int j = statements.size() - 1;

                while (i < j) {
                    Statement s = (Statement) statements.get(i);
                    statements.set(i, statements.get(j));
                    statements.set(j, s);
                    i++;
                    j--;
                }
            }
        }
    }

    /**
     * For inserts and updates we figure out values (they might be hidden)
     * and add the columns necessary. <code>addColumn will figure out
     * which tables need to be included.
     */
    private void addColumns() {
        if ((action == ACT_UPDATE) || (action == ACT_INSERT)) {
            List updatedFields = updateDesc.getUpdatedFields();
            int size = (updatedFields != null) ? updatedFields.size() : 0;
            for (int i = 0; i < size; i++) {
                LocalFieldDesc f = (LocalFieldDesc) updatedFields.get(i);
                Object value = batch ? f : updateDesc.getAfterValue(f);
                addColumn(f, value);
            }
        }
    }

    private void addConstraints(UpdateStatement statement,
                                ArrayList localFields,
                                ArrayList foreignFields,
                                ArrayList columns) {

        boolean isBeforeImageRequired = updateDesc.isBeforeImageRequired();
        for (int i = 0; i < localFields.size(); i++) {
            LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
            LocalFieldDesc ff = (LocalFieldDesc) foreignFields.get(i);
            ColumnElement ce = (ColumnElement) columns.get(i);

            addConstraint(statement, lf, ff, ce, isBeforeImageRequired);
        }

        // Add the constraint on the version field if needed.
        if (getConfig().hasVersionConsistency() && action != ACT_INSERT) {
            QueryTable table = (QueryTable) statement.getQueryTables().get(0);
            LocalFieldDesc versionField = table.getTableDesc().getVersionField();
            ColumnElement ce = (ColumnElement) versionField.getColumnElements().next();

            addConstraint(statement, versionField, versionField, ce, false);
        }

        statement.markConstraintAdded();
    }

    private void addConstraint(UpdateStatement statement,
                               LocalFieldDesc lf,
                               LocalFieldDesc ff,
                               ColumnElement ce,
                               boolean isBeforeImageRequired) {

        if (action != ACT_INSERT) {
            if (batch) {
                statement.addConstraint(ce, lf, ff);
            }
            else {
                Object value = isBeforeImageRequired ?
                    updateDesc.getBeforeValue(ff) : updateDesc.getAfterValue(ff);
                statement.addConstraint(lf, value);
            }
        } else {
            Object value = batch ? ff : updateDesc.getAfterValue(ff);
            statement.addColumn(ce, value);
        }
    }

    private void addSecondaryTableConstraint(UpdateStatement statement) {
        QueryTable table = (QueryTable) statement.getQueryTables().get(0);
        ReferenceKeyDesc key = table.getTableDesc().getPrimaryTableKey();

        ArrayList localFields = key.getReferencingKey().getFields();
        ArrayList foreignFields = key.getReferencedKey().getFields();
        ArrayList columns = key.getReferencingKey().getColumns();

        addConstraints(statement, localFields, foreignFields, columns);
    }

    private void addBasetableConstraint(UpdateStatement statement) {
        QueryTable table = (QueryTable) statement.getQueryTables().get(0);
        KeyDesc key = table.getTableDesc().getKey();

        ArrayList localFields = key.getFields();
        ArrayList columns = key.getColumns();

        addConstraints(statement, localFields, localFields, columns);
    }

    private void processRelatedStatements(UpdateStatement statement) {
        ArrayList secondaryTableStatements = statement.getSecondaryTableStatements();

        if (secondaryTableStatements != null) {
            for (int i = 0; i < secondaryTableStatements.size(); i++) {
                UpdateStatement secondaryTableStatement = (UpdateStatement) secondaryTableStatements.get(i);

                if (!secondaryTableStatement.isConstraintAdded()) {
                    processRelatedStatements(secondaryTableStatement);

                    addSecondaryTableConstraint(secondaryTableStatement);
                }
            }
        }
    }

    protected void processStatements() {
        int size = statements.size();

        if (size > 1) {
            super.processStatements();

            for (int i = 0; i < size; i++) {
                UpdateStatement statement = (UpdateStatement) statements.get(i);

                if (!statement.isConstraintAdded())
                    processRelatedStatements(statement);
            }
        }

        UpdateStatement masterStatement = null;

        if (size == 1)
            masterStatement = (UpdateStatement) statements.get(0);
        else {
            // Look for the master statement. It should be the one
            // with no constraints added.
            for (int i = 0; i < size; i++) {
                masterStatement = (UpdateStatement) statements.get(i);

                if (!masterStatement.isConstraintAdded()) break;
            }
        }

        if (action != ACT_INSERT)
            addBasetableConstraint(masterStatement);

        if ((action != ACT_INSERT) && (updateDesc.getConcurrency() != null))
            updateDesc.getConcurrency().update(this);
    }

    private void processJoinTables() {
        Collection fields = updateDesc.getUpdatedJoinTableFields();

        if (fields == null) return;

        Iterator fieldIter = fields.iterator();

        ArrayList deleteStatements = new ArrayList();
        ArrayList insertStatements = new ArrayList();

        while (fieldIter.hasNext()) {
            ForeignFieldDesc f = (ForeignFieldDesc) fieldIter.next();
            Collection descs = updateDesc.getUpdateJoinTableDescs(f);
            Iterator descIter = descs.iterator();

            ColumnElement c = (ColumnElement) f.assocLocalColumns.get(0);
            QueryTable t = addQueryTable(config.findTableDesc(c.getDeclaringTable()));

            while (descIter.hasNext()) {
                UpdateJoinTableDesc desc = (UpdateJoinTableDesc) descIter.next();
                int action = getAction(desc.getAction());

                UpdateStatement s = (UpdateStatement) createStatement(t);
                s.setAction(action);

                if (action == ACT_INSERT) {
                    insertStatements.add(s);
                } else if (action == ACT_DELETE) {

                    // RESOLVE: There are redundant deletes from join tables that causes
                    // update to fail with no rows affected. To work around this problem
                    // for now, we set the minAffectedRows to 0.
                    // We need to figure out why there are redundant deletes.

                    s.minAffectedRows = 0;
                    deleteStatements.add(s);
                }

                s.addLocalConstraints(action, f, desc.getParentStateManager());
                s.addForeignConstraints(action, f, desc.getForeignStateManager());
            }
        }

        // All join table delete statements have to go first and all
        // join table insert statements have to go last.

        ArrayList oldStatements = statements;
        statements = deleteStatements;
        statements.addAll(oldStatements);
        statements.addAll(insertStatements);
    }

    protected Statement newStatement() {
        return new UpdateStatement(store.getVendorType(), this, batch);
    }

    /**
     * Determines if the amount of batched operations exceeded a threshold.
     * @param tran the transaction
     * @return true if the amount of batched operations exceeded a threshold
     */
    public boolean checkBatchThreshold(Transaction tran)
    {
        for (int i = 0, size = statements.size(); i < size; i++) {
            UpdateStatement updateStatement = (UpdateStatement) statements.get(i);
            if (updateStatement.exceedsBatchThreshold(tran))
                return true;
        }
        return false;
    }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish UpdateQueryPlan.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.