Package org.conserve.tools

Source Code of org.conserve.tools.Updater$TableId

/*******************************************************************************
* Copyright (c) 2009, 2012 Erik Berglund.
*  
*      This file is part of Conserve.
*  
*       Conserve 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.
*  
*       Conserve 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 Conserve.  If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package org.conserve.tools;

import java.io.IOException;
import java.lang.reflect.Array;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.conserve.adapter.AdapterBase;
import org.conserve.connection.ConnectionWrapper;
import org.conserve.tools.protection.ProtectionManager;

/**
* Class responsible for updating objects.
*
* @author Erik Berglund
*
*/
public class Updater
{

  private AdapterBase adapter;

  public Updater(AdapterBase adapter)
  {
    this.adapter = adapter;
  }

  /**
   * Update the object with the given database ID with the new values. Values
   * that are not specified in nuValues will be left unchanged.
   *
   * @param cw
   * @param nuValues
   *            the object that holds the new values to be assigned to the
   *            database row.
   * @param tableName
   * @param databaseId
   * @throws SQLException
   * @throws IOException
   */
  public void updateObject(ConnectionWrapper cw, Object nuValues,
      String tableName, Long databaseId,
      DelayedInsertionBuffer delayBuffer) throws SQLException
  {
    if (nuValues.getClass().isArray())
    {
      updateArray(cw, nuValues, databaseId, delayBuffer);
    }
    else
    {
      ObjectStack oStack = new ObjectStack(adapter, nuValues.getClass(),
          nuValues);
      for (int stackIndex = oStack.getSize() - 1; stackIndex > 0; stackIndex--)
      {

        ObjectRepresentation rep = oStack.getRepresentation(stackIndex);
        Long repId = adapter.getPersist().getCastId(
            rep.getRepresentedClass(),
            oStack.getActualRepresentation().getRepresentedClass(),
            databaseId, cw);
        rep.setId(repId);
        // get all existing reference values
        HashMap<String, Long> refValues = getReferenceValues(cw, rep);
        ArrayList<Object> values = new ArrayList<Object>();
        StringBuilder updateStatement = new StringBuilder();
        List<String> deleteList = new ArrayList<String>();
        for (Integer index : rep)
        {
          if (updateStatement.length() > 0)
          {
            updateStatement.append(",");
          }
          String name = rep.getPropertyName(index);
          Object value = rep.getPropertyValue(index);
          Class<?> referenceType = rep.getReturnType(index);
          updateStatement.append(name);
          updateStatement.append(" = ? ");
          if (ObjectTools.isPrimitive(referenceType))
          {
            // put the new value in the statement
            values.add(value);
          }
          else
          {
            // save the new value
            Long propertyId = adapter.getPersist()
                .saveObjectUnprotected(cw, value, delayBuffer);
            propertyId = adapter.getPersist()
                .getCastId(referenceType, value.getClass(),
                    propertyId, cw);
            if (propertyId == null)
            {
              break;
            }
            if (!propertyId.equals(refValues.get(name)))
            {
              // the new value is different from the existing
              // value, delete
              deleteList.add(name);
            }
            // protect the object
            adapter.getPersist()
                .getProtectionManager()
                .protectObjectInternalConditional(
                    rep.getTableName(),
                    rep.getId(),rep.getPropertyName(index),
                    NameGenerator.getTableName(
                        value.getClass(), adapter),
                    propertyId,
                    ObjectTools.getSystemicName(value
                        .getClass()), cw);
            // save the reference
            values.add(propertyId);
          }
        }
        // add all non-primitive null values to the deleteList
        for (int y = 0; y < rep.getPropertyCount(); y++)
        {
          if (!rep.isPrimitive(y))
          {
            if (rep.getPropertyValue(y) == null)
            {
              deleteList.add(rep.getPropertyName(y));
            }
          }
        }
        // delete complex values, if they exists
        if (deleteList.size() > 0)
        {
          nullProperties(cw, deleteList, refValues, oStack, rep);
        }
        if (updateStatement.length() > 0)
        {
          PreparedStatement pStatement = null;
          StringBuilder fullStatement = new StringBuilder("UPDATE ");
          fullStatement.append(rep.getTableName());
          fullStatement.append(" SET ");
          fullStatement.append(updateStatement);
          fullStatement.append(" WHERE ");

          fullStatement.append(Defaults.ID_COL);
          fullStatement.append(" = ?");
          pStatement = cw.prepareStatement(fullStatement.toString());
          for (int t = 0; t < values.size(); t++)
          {
            Object value = values.get(t);
            Tools.setParameter(pStatement, value.getClass(), t + 1,
                value);
          }
          pStatement.setLong(values.size() + 1, rep.getId());
          Tools.logFine(pStatement);

          int updatedCount = pStatement.executeUpdate();
          pStatement.close();
          if (updatedCount != 1)
          {
            throw new SQLException("Wrong number of rows updated: "
                + updatedCount);
          }
        }
      }
    }
  }

  /**
   * Get all reference (non-primitive) values for a given table entry.
   *
   * @param rep
   * @return
   * @throws SQLException
   */
  private HashMap<String, Long> getReferenceValues(ConnectionWrapper cw,
      ObjectRepresentation rep) throws SQLException
  {
    HashMap<String, Long> res = new HashMap<String, Long>();
    StringBuilder query = new StringBuilder("SELECT ");
    // get reference values
    ArrayList<String> refNames = new ArrayList<String>();
    for (int x = 0; x < rep.getPropertyCount(); x++)
    {
      if (!ObjectTools.isPrimitive(rep.getReturnType(x)))
      {
        refNames.add(rep.getPropertyName(x));
      }
    }
    if (refNames.size() > 0)
    {
      // add the names of the reference values
      for (int x = 0; x < refNames.size(); x++)
      {
        query.append(refNames.get(x));
        if (x < (refNames.size() - 1))
        {
          query.append(",");
        }
      }
      query.append(" FROM ");
      query.append(rep.getTableName());
      query.append(" WHERE ");
      query.append(Defaults.ID_COL);
      query.append(" = ?");
      PreparedStatement ps = cw.prepareStatement(query.toString());
      ps.setLong(1, rep.getId());
      try
      {
        ResultSet rs = ps.executeQuery();
        if (rs.next())
        {
          // add name-value pairs to res
          ResultSetMetaData rsmd = rs.getMetaData();
          for (int x = 1; x <= rsmd.getColumnCount(); x++)
          {
            if (rs.getObject(x) != null)
            {
              res.put(rsmd.getColumnName(x).toUpperCase(),
                  rs.getLong(x));
            }
          }
          if (rs.next())
          {
            throw new SQLException("Found more than one row in "
                + rep.getTableName() + " with id "
                + rep.getId());
          }
        }
        else
        {
          throw new SQLException("Found no row in "
              + rep.getTableName() + " with id " + rep.getId());
        }
      }
      finally
      {
        ps.close();
      }
    }
    return res;
  }

  /**
   * Update an array with a given ID.
   *
   * @param cw
   * @param nuValues
   *            an array of the new values to store under the given id.
   * @param databaseId
   *            the id of the array to update.
   * @throws SQLException
   * @throws IOException
   */
  private void updateArray(ConnectionWrapper cw, Object nuValues,
      Long databaseId, DelayedInsertionBuffer delayBuffer)
      throws SQLException
  {
    // if the new objects are non-primitve, save them and keep their ids
    ArrayList<TableId> nuIds = new ArrayList<TableId>();
    if (!ObjectTools.isPrimitive(nuValues.getClass().getComponentType()))
    {
      int length = Array.getLength(nuValues);
      for (int x = 0; x < length; x++)
      {
        Object nuObject = Array.get(nuValues, x);
        Long id = adapter.getPersist().saveObjectUnprotected(cw,
            nuObject, delayBuffer);
        if (id == null)
        {
          break;
        }
        nuIds.add(new TableId(NameGenerator.getTableName(nuObject,
            adapter), id));
      }
    }
    // Get type of existing array
    ArrayLoader arrayLoader = new ArrayLoader(adapter, adapter.getPersist()
        .getCache(), cw);
    arrayLoader.loadArray(databaseId);
    String ownerTable = arrayLoader.getRelationalTableName();
    Class<?> componentType = arrayLoader.getArray().getClass()
        .getComponentType();
    // List all members of the existing array
    ProtectionManager protecter = adapter.getPersist()
        .getProtectionManager();
    for (int x = 0; x < arrayLoader.getLength(); x++)
    {
      Object component = arrayLoader.getEntry(x);
      // if they are non-primitive
      if (!ObjectTools.isPrimitive(component.getClass()))
      {
        // unprotect them
        Long ownerId = arrayLoader.getRelationalIds().get(x);
        String propertyTable = NameGenerator.getTableName(component,
            adapter);
        Long propertyId = adapter.getPersist().getId(component);
        protecter.unprotectObjectInternal(ownerTable, ownerId,
            propertyTable, propertyId, cw);
        if (!protecter.isProtected(propertyTable, propertyId, cw)
            && !nuIds.contains(new TableId(propertyTable,
                propertyId)))
        {
          // Delete them if they have no other protection
          adapter.getPersist().deleteObject(component.getClass(),
              propertyId, cw);
        }
      }
    }
    // delete the old array_member entries
    StringBuilder removeMemberEntries = new StringBuilder("DELETE FROM ");
    removeMemberEntries.append(NameGenerator.getArrayMemberTableName(
        componentType, adapter));
    removeMemberEntries.append(" WHERE ");
    removeMemberEntries.append(Defaults.ARRAY_MEMBER_ID);
    removeMemberEntries.append(" = ? ");
    PreparedStatement removeStmt = cw.prepareStatement(removeMemberEntries
        .toString());
    removeStmt.setLong(1, databaseId);
    Tools.logFine(removeStmt);
    removeStmt.execute();
    removeStmt.close();

    adapter.getPersist().getArrayEntryWriter()
        .addArrayEntries(cw, databaseId, nuValues, delayBuffer);
  }

  /**
   * Delete named entries from a named table and a row identified by
   * databaseId.
   *
   * @param cw
   *            the connection wrapper to use.
   * @param nullValues
   *            the list of named values to delete.
   * @throws SQLException
   */
  private void nullProperties(ConnectionWrapper cw, List<String> nullValues,
      HashMap<String, Long> refValues, ObjectStack oStack,
      ObjectRepresentation rep) throws SQLException
  {
    ObjectRepresentation actual = oStack.getActualRepresentation();
    rep.setId(adapter.getPersist().getCastId(rep.getRepresentedClass(),
        actual.getRepresentedClass(), actual.getId(), cw));

    // set all the values to NULL
    PreparedStatement ps = null;
    StringBuilder statement = new StringBuilder("UPDATE ");
    statement.append(rep.getTableName());
    statement.append(" SET ");
    StringBuilder subStatement = new StringBuilder();
    for (String name : nullValues)
    {
      if (subStatement.length() > 0)
      {
        subStatement.append(",");
      }
      subStatement.append(name);
      subStatement.append(" = NULL");
    }
    statement.append(subStatement);
    statement.append(" WHERE ");

    statement.append(Defaults.ID_COL);
    statement.append(" = ?");
    ps = cw.prepareStatement(statement.toString());
    ps.setLong(1, rep.getId());
    Tools.logFine(ps);
    int updatedCount = ps.executeUpdate();
    ps.close();
    if (updatedCount != 1)
    {
      throw new SQLException("Wrong number of rows updated: "
          + updatedCount);
    }
    // unprotect and optionally delete discarded values of the object
    for (String nValue : nullValues)
    {
      Long propertyId = refValues.get(nValue);
      if (propertyId != null)
      {
        ClassIdTuple actualNameId = adapter.getPersist()
            .getRealTableNameAndId(cw, rep.getReturnType(nValue),
                propertyId);

        adapter.getPersist()
            .getProtectionManager()
            .unprotectObjectInternal(rep.getTableName(),
                rep.getId(),
                actualNameId.getTableName(adapter),
                actualNameId.getId(), cw);
        if (!adapter
            .getPersist()
            .getProtectionManager()
            .isProtected(actualNameId.getTableName(adapter),
                actualNameId.getId(), cw))
        {
          adapter.getPersist().deleteObject(
              actualNameId.getRepresentedClass(),
              actualNameId.getId(), cw);
        }
      }
    }
  }

  /**
   * A pair, one table name and one table id.
   *
   * @author Erik Berglund
   */
  private static class TableId
  {
    private String tableName;
    private Long id;

    public TableId(String tableName, Long id)
    {
      this.id = id;
      this.tableName = tableName;
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj)
    {
      if (obj instanceof TableId)
      {
        TableId other = (TableId) obj;
        if (tableName.equals(other.tableName) && id.equals(other.id))
        {
          return true;
        }
      }
      return false;
    }

  }
}
TOP

Related Classes of org.conserve.tools.Updater$TableId

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.