Package org.apache.openjpa.jdbc.meta.strats

Source Code of org.apache.openjpa.jdbc.meta.strats.ColumnVersionStrategy

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.   
*/
package org.apache.openjpa.jdbc.meta.strats;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Comparator;

import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.VersionMappingInfo;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ColumnIO;
import org.apache.openjpa.jdbc.schema.Index;
import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.Row;
import org.apache.openjpa.jdbc.sql.RowManager;
import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.MetaDataException;

/**
* Uses a single column and corresponding version object.
*
* @author Marc Prud'hommeaux
*/
public abstract class ColumnVersionStrategy
    extends AbstractVersionStrategy {

    private static final Localizer _loc = Localizer.forPackage
        (ColumnVersionStrategy.class);

    /**
     * Return the code from {@link JavaTypes} for the version values this
     * strategy uses. This method is only used during mapping installation.
     */
    protected abstract int getJavaType();

    /**
     * Return the next version given the current one, which may be null.
     */
    protected abstract Object nextVersion(Object version);

    /**
     * Compare the two versions. Defaults to assuming the version objects
     * implement {@link Comparable}.
     *
     * @see Comparator#compare
     */
    protected int compare(Object v1, Object v2) {
        if (v1 == v2)
            return 0;
        if (v1 == null)
            return -1;
        if (v2 == null)
            return 1;

        if (v1.getClass() != v2.getClass()) {
            if (v1 instanceof Number && !(v1 instanceof BigDecimal))
                v1 = new BigDecimal(((Number) v1).doubleValue());

            if (v2 instanceof Number && !(v2 instanceof BigDecimal))
                v2 = new BigDecimal(((Number) v2).doubleValue());
        }

        return ((Comparable) v1).compareTo(v2);
    }

    public void map(boolean adapt) {
        ClassMapping cls = vers.getClassMapping();
        if (cls.getJoinablePCSuperclassMapping() != null
            || cls.getEmbeddingMetaData() != null)
            throw new MetaDataException(_loc.get("not-base-vers", cls));

        VersionMappingInfo info = vers.getMappingInfo();
        info.assertNoJoin(vers, true);
        info.assertNoForeignKey(vers, !adapt);
        info.assertNoUnique(vers, false);

        Column tmplate = new Column();
        tmplate.setJavaType(getJavaType());
        tmplate.setName("versn");

        Column[] cols = info.getColumns(vers, new Column[]{ tmplate }, adapt);
        cols[0].setVersionStrategy(this);
        vers.setColumns(cols);
        vers.setColumnIO(info.getColumnIO());

        Index idx = info.getIndex(vers, cols, adapt);
        vers.setIndex(idx);
    }

    public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
        throws SQLException {
        Column[] cols = vers.getColumns();
        ColumnIO io = vers.getColumnIO();
        Object initial = nextVersion(null);
        Row row = rm.getRow(vers.getClassMapping().getTable(),
            Row.ACTION_INSERT, sm, true);
        for (int i = 0; i < cols.length; i++)
            if (io.isInsertable(i, initial == null))
                row.setObject(cols[i], initial);

        // set initial version into state manager
        Object nextVersion;
        nextVersion = initial;
        sm.setNextVersion(nextVersion);
    }

    public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
        throws SQLException {
        Column[] cols = vers.getColumns();
        if (cols == null || cols.length == 0 ||
            !sm.isDirty() && !sm.isVersionUpdateRequired())
            return;

        Object curVersion = sm.getVersion();
        Object nextVersion = nextVersion(curVersion);

        Row row = rm.getRow(vers.getClassMapping().getTable(),
            Row.ACTION_UPDATE, sm, true);
        row.setFailedObject(sm.getManagedInstance());

        // set where and update conditions on row
        for (int i = 0; i < cols.length; i++) {
            if (curVersion != null && sm.isVersionCheckRequired())
                row.whereObject(cols[i], curVersion);
            if (vers.getColumnIO().isUpdatable(i, nextVersion == null))
                row.setObject(cols[i], nextVersion);
        }

        if (nextVersion != null)
            sm.setNextVersion(nextVersion);
    }

    public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
        throws SQLException {
        Row row = rm.getRow(vers.getClassMapping().getTable(),
            Row.ACTION_DELETE, sm, true);
        row.setFailedObject(sm.getManagedInstance());
        Column[] cols = vers.getColumns();

        Object curVersion = sm.getVersion();
        Object cur;
        for (int i = 0; i < cols.length; i++) {
            if (cols.length == 1 || curVersion == null)
                cur = curVersion;
            else
                cur = ((Object[]) curVersion)[i];

            // set where and update conditions on row
            if (cur != null)
                row.whereObject(cols[i], cur);
        }
    }

    public boolean select(Select sel, ClassMapping mapping) {
        sel.select(vers.getColumns());
        return true;
    }

    public Object load(OpenJPAStateManager sm, JDBCStore store, Result res)
        throws SQLException {
        // typically if one version column is in the result, they all are, so
        // optimize by checking for the first one before doing any real work
        Column[] cols = vers.getColumns();
        if (!res.contains(cols[0]))
            return null;

        Object version = null;
        if (cols.length > 0)
            version = new Object[cols.length];
        Object cur;
        for (int i = 0; i < cols.length; i++) {
            if (i > 0 && !res.contains(cols[i]))
                return null;
            cur = res.getObject(cols[i], -1, null);
            if (cols.length == 1)
                version = cur;
            else
                ((Object[]) version)[i] = cur;
        }
        // OPENJPA-662 Allow a null StateManager because this method may just be
        // invoked to get the result of projection query
        if (sm != null)
          sm.setVersion(version);
        return version;
    }

    public boolean checkVersion(OpenJPAStateManager sm, JDBCStore store,
        boolean updateVersion)
        throws SQLException {
        Column[] cols = vers.getColumns();
        Select sel = store.getSQLFactory().newSelect();
        sel.select(cols);
        sel.wherePrimaryKey(sm.getObjectId(), vers.getClassMapping(), store);

        Result res = sel.execute(store, null);
        try {
            if (!res.next())
                return false;

            Object memVersion = sm.getVersion();
            Object dbVersion = null;
            if (cols.length > 1)
                dbVersion = new Object[cols.length];

            boolean refresh = false;
            Object mem, db;
            for (int i = 0; i < cols.length; i++) {
                db = res.getObject(cols[i], -1, null);
                if (cols.length == 1)
                    dbVersion = db;
                else
                    ((Object[]) dbVersion)[i] = db;

                // if we haven't already determined that we need a refresh,
                // check if the mem version is earlier than the db one
                if (!refresh) {
                    if (cols.length == 1 || memVersion == null)
                        mem = memVersion;
                    else
                        mem = ((Object[]) memVersion)[i];

                    if (mem == null || (db != null && compare(mem, db) < 0))
                        refresh = true;
                }
            }

            if (updateVersion)
                sm.setVersion(dbVersion);
            return !refresh;
        } finally {
            res.close();
        }
    }

    public int compareVersion(Object v1, Object v2) {
        if (v1 == v2)
            return StoreManager.VERSION_SAME;
        if (v1 == null || v2 == null)
            return StoreManager.VERSION_DIFFERENT;

        int cmp = compare(v1, v2);
        if (cmp < 0)
            return StoreManager.VERSION_EARLIER;
        if (cmp > 0)
            return StoreManager.VERSION_LATER;
        return StoreManager.VERSION_SAME;
    }
}
TOP

Related Classes of org.apache.openjpa.jdbc.meta.strats.ColumnVersionStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.