Package se.unlogic.standardutils.dao

Source Code of se.unlogic.standardutils.dao.SimplifiedOneToManyRelation

/*******************************************************************************
* Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0-standalone.html
******************************************************************************/
package se.unlogic.standardutils.dao;

import se.unlogic.standardutils.collections.CollectionUtils;
import se.unlogic.standardutils.dao.annotations.DAOManaged;
import se.unlogic.standardutils.dao.annotations.Key;
import se.unlogic.standardutils.dao.annotations.SimplifiedRelation;
import se.unlogic.standardutils.dao.enums.Order;
import se.unlogic.standardutils.dao.querys.ArrayListQuery;
import se.unlogic.standardutils.dao.querys.PreparedStatementQuery;
import se.unlogic.standardutils.dao.querys.UpdateQuery;
import se.unlogic.standardutils.populators.BeanStringPopulator;
import se.unlogic.standardutils.populators.QueryParameterPopulator;
import se.unlogic.standardutils.reflection.ReflectionUtils;
import se.unlogic.standardutils.string.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class SimplifiedOneToManyRelation<LocalType, RemoteType> implements OneToManyRelation<LocalType, RemoteType> {

  private final AnnotatedDAO<LocalType> localDAO;
  private final Field field;

  private String selectSQL;
  private String insertSQL;
  private String deleteSQL;

  private boolean preserveListOrder;
  private String indexColumnName;
 
  private QueryParameterPopulator<RemoteType> queryParameterPopulator;
  private Method preparedStatementMethod;

  private BeanResultSetPopulator<RemoteType> beanResultSetPopulator;

  private Field keyField;
  private Column<LocalType, ?> keyColumn;

  private final String remoteTableName;
  private String remoteKeyColumnName;
  private final String remoteValueColumnName;
  private Order order;

  private boolean initialized;

  @SuppressWarnings("unchecked")
  public SimplifiedOneToManyRelation(Class<LocalType> beanClass, Class<RemoteType> remoteClass, Field field, AnnotatedDAO<LocalType> localDAO, List<? extends BeanStringPopulator<?>> typePopulators, List<? extends QueryParameterPopulator<?>> queryParameterPopulators) {

    super();
    this.localDAO = localDAO;
    this.field = field;

    SimplifiedRelation simplifiedRelation = field.getAnnotation(SimplifiedRelation.class);

    remoteKeyColumnName = simplifiedRelation.remoteKeyColumnName();
    remoteValueColumnName = simplifiedRelation.remoteValueColumnName();
    order = simplifiedRelation.order();

    if(simplifiedRelation.addTablePrefix()){
     
      if(simplifiedRelation.deplurifyTablePrefix() && localDAO.getTableName().endsWith("s")){
       
        remoteTableName = localDAO.getTableName().substring(0, localDAO.getTableName().length()-1) + simplifiedRelation.table();
       
      }else{
       
        remoteTableName = localDAO.getTableName() + simplifiedRelation.table();
      }
    }else{
     
      remoteTableName = simplifiedRelation.table();
    }
   
    if (!StringUtils.isEmpty(simplifiedRelation.keyField())) {

      try {
        keyField = ReflectionUtils.getField(beanClass, simplifiedRelation.keyField());

        if (keyField == null) {

          throw new RuntimeException("Unable to find field " + simplifiedRelation.keyField() + " in " + beanClass.getClass());
        }

      } catch (SecurityException e) {

        throw new RuntimeException(e);

      }

    } else {

      List<Field> fields = ReflectionUtils.getFields(beanClass);

      for (Field localBeanField : fields) {

        if (localBeanField.isAnnotationPresent(DAOManaged.class) && localBeanField.isAnnotationPresent(Key.class)) {

          if (this.keyField == null) {

            keyField = localBeanField;

          } else {

            throw new RuntimeException("Multiple fields marked with @Key annotation found in class " + beanClass + " therefore keyField has to set on the @SimplifiedRelation annotation of field " + field.getName());
          }
        }
      }
    }

    if (queryParameterPopulators != null) {

      for (QueryParameterPopulator<?> queryParameterPopulator : queryParameterPopulators) {

        if (queryParameterPopulator.getType().equals(remoteClass)) {

          this.queryParameterPopulator = (QueryParameterPopulator<RemoteType>) queryParameterPopulator;
        }
      }
    }

    if (this.queryParameterPopulator == null) {

      preparedStatementMethod = PreparedStatementQueryMethods.getQueryMethod(remoteClass);

      if (preparedStatementMethod == null) {

        throw new RuntimeException("Unable to to find a query parameter populator or prepared statement method matching " + remoteClass + " of @SimplfiedRelation and @OneToMany annotated field " + field.getName() + " in " + beanClass);
      }
    }

    if (typePopulators != null) {

      for (BeanStringPopulator<?> typePopulator : typePopulators) {

        if (typePopulator.getType().equals(remoteClass)) {

          beanResultSetPopulator = new TypeBasedResultSetPopulator<RemoteType>((BeanStringPopulator<RemoteType>) typePopulator, remoteValueColumnName);
        }
      }
    }

    if (beanResultSetPopulator == null) {

      Method resultSetMethod = ResultSetMethods.getColumnNameMethod(remoteClass);

      if (resultSetMethod != null) {

        beanResultSetPopulator = new MethodBasedResultSetPopulator<RemoteType>(resultSetMethod, remoteValueColumnName);

      } else {

        throw new RuntimeException("Unable to to find a type populator or resultset method matching " + remoteClass + " of @SimplfiedRelation and @OneToMany annotated field " + field.getName() + " in " + beanClass);
      }
    }
   
    if(simplifiedRelation.preserveListOrder()){
     
      if(StringUtils.isEmpty(simplifiedRelation.indexColumn())){
       
        throw new RuntimeException("Preserve list order enabled but no index column specified for @SimplifiedRelation annotated field " + field.getName() + " in " + beanClass);
      }
     
      preserveListOrder = true;
      indexColumnName = simplifiedRelation.indexColumn();
    }
  }

  private void init() {

    this.keyColumn = localDAO.getColumn(keyField);

    if (StringUtils.isEmpty(remoteKeyColumnName)) {

      remoteKeyColumnName = keyColumn.getColumnName();
    }

    this.deleteSQL = "DELETE FROM " + remoteTableName + " WHERE " + remoteKeyColumnName + "=?";

    if(preserveListOrder){
     
      this.selectSQL = "SELECT * FROM " + remoteTableName + " WHERE " + remoteKeyColumnName + " = ? ORDER BY " + indexColumnName + " " + order;
      this.insertSQL = "INSERT INTO " + remoteTableName + "(" + remoteKeyColumnName + "," + remoteValueColumnName + "," + indexColumnName + ") VALUES (?,?,?)";
     
    }else{
     
      this.selectSQL = "SELECT * FROM " + remoteTableName + " WHERE " + remoteKeyColumnName + " = ? ORDER BY " + remoteValueColumnName + " " + order;
      this.insertSQL = "INSERT INTO " + remoteTableName + "(" + remoteKeyColumnName + "," + remoteValueColumnName + ") VALUES (?,?)";
    }
   
    this.initialized = true;
  }

  /*
   * (non-Javadoc)
   *
   * @see se.unlogic.utils.dao.OneToManyRelation#setValue(LocalType, java.sql.Connection, java.lang.reflect.Field[])
   */
  public void getRemoteValue(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException {

    if (!initialized) {
      init();
    }

    try {
      ArrayListQuery<RemoteType> query = new ArrayListQuery<RemoteType>(connection, false, selectSQL, beanResultSetPopulator);

      setKey(query, bean);

      ArrayList<RemoteType> list = query.executeQuery();

      if (list != null) {

        CollectionUtils.removeNullValues(list);
      }

      field.set(bean, list);

    } catch (IllegalArgumentException e) {

      throw new RuntimeException(e);

    } catch (IllegalAccessException e) {

      throw new RuntimeException(e);
    }
  }

  private void setKey(PreparedStatementQuery query, LocalType bean) throws SQLException {

    if (keyColumn.getQueryParameterPopulator() != null) {

      keyColumn.getQueryParameterPopulator().populate(query, 1, bean);

    } else {

      try {
        keyColumn.getQueryMethod().invoke(query, 1, keyColumn.getBeanValue(bean));

      } catch (IllegalArgumentException e) {

        throw new RuntimeException(e);

      } catch (IllegalAccessException e) {

        throw new RuntimeException(e);

      } catch (InvocationTargetException e) {

        throw new RuntimeException(e);
      }
    }
  }

  private void setValue(RemoteType value, UpdateQuery query) throws SQLException {

    if (queryParameterPopulator != null) {

      queryParameterPopulator.populate(query, 2, value);

    } else {

      try {
        preparedStatementMethod.invoke(query, 2, value);

      } catch (IllegalArgumentException e) {

        throw new RuntimeException(e);

      } catch (IllegalAccessException e) {

        throw new RuntimeException(e);

      } catch (InvocationTargetException e) {

        throw new RuntimeException(e);
      }
    }

  }

  /*
   * (non-Javadoc)
   *
   * @see se.unlogic.utils.dao.OneToManyRelation#add(LocalType, java.sql.Connection, java.lang.reflect.Field[])
   */
  @SuppressWarnings("unchecked")
  public void add(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException {

    if (!initialized) {
      init();
    }

    try {
      List<RemoteType> values = (List<RemoteType>) field.get(bean);

      if (values != null) {

        int listIndex = 0;
       
        for (RemoteType value : values) {

          UpdateQuery query = new UpdateQuery(connection, false, insertSQL);

          setKey(query, bean);

          setValue(value, query);

          if(preserveListOrder){
           
            query.setInt(3, listIndex);
            listIndex++;
          }
         
          query.executeUpdate();
        }
      }

    } catch (IllegalArgumentException e) {

      throw new RuntimeException(e);

    } catch (IllegalAccessException e) {

      throw new RuntimeException(e);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see se.unlogic.utils.dao.OneToManyRelation#update(LocalType, java.sql.Connection, java.lang.reflect.Field[])
   */
  public void update(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException {

    if (!initialized) {
      init();
    }

    UpdateQuery query = new UpdateQuery(connection, false, deleteSQL);

    setKey(query, bean);

    query.executeUpdate();

    this.add(bean, connection, relationQuery);
  }

  public static <LT, RT> OneToManyRelation<LT, RT> getGenericInstance(Class<LT> beanClass, Class<RT> remoteClass, Field field, AnnotatedDAO<LT> localDAO, List<? extends BeanStringPopulator<?>> typePopulators, List<? extends QueryParameterPopulator<?>> queryParameterPopulators) {

    return new SimplifiedOneToManyRelation<LT, RT>(beanClass, remoteClass, field, localDAO, typePopulators, queryParameterPopulators);
  }
}
TOP

Related Classes of se.unlogic.standardutils.dao.SimplifiedOneToManyRelation

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.