Package com.alvazan.orm.impl.meta.data

Source Code of com.alvazan.orm.impl.meta.data.NoSqlProxyImpl

package com.alvazan.orm.impl.meta.data;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javassist.util.proxy.MethodHandler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alvazan.orm.api.exc.RowNotFoundException;
import com.alvazan.orm.api.z5api.NoSqlSession;
import com.alvazan.orm.api.z8spi.KeyValue;
import com.alvazan.orm.api.z8spi.Row;
import com.alvazan.orm.api.z8spi.conv.Converter;
import com.alvazan.orm.api.z8spi.iter.AbstractCursor;
import com.alvazan.orm.api.z8spi.iter.AbstractCursor.Holder;
import com.alvazan.orm.api.z8spi.iter.IterableWrappingCursor;
import com.alvazan.orm.api.z8spi.meta.DboColumnIdMeta;
import com.alvazan.orm.api.z8spi.meta.DboTableMeta;
import com.alvazan.orm.impl.meta.data.collections.CacheLoadCallback;

public class NoSqlProxyImpl<T> implements MethodHandler {

  private static final Logger log = LoggerFactory.getLogger(NoSqlProxyImpl.class);
  private NoSqlSession session;
  private Object entityId;
  private Method idMethod;
  private MetaAbstractClass<T> classMeta;
  private boolean isInitialized = false;
  private CacheLoadCallback cacheLoadCallback;
  private Map<Field, Object> indexFieldToOriginalValue = new HashMap<Field, Object>();
 
  public NoSqlProxyImpl(NoSqlSession session, MetaAbstractClass<T> classMeta, Object entityId, CacheLoadCallback cacheLoadCallback) {
    if(classMeta.getColumnFamily() == null)
      throw new IllegalArgumentException("column family in the classMeta parameter cannot be null");
    if(session == null && cacheLoadCallback == null)
      throw new IllegalArgumentException("Need session or cacheCallback");
    else if(session != null && cacheLoadCallback != null)
      throw new IllegalArgumentException("You must supply a cacheLoadCallback OR a session but NOT both...give us session and we load it, give us cacheLoad and we tell you to load your list of proxies when needed");
    this.session = session;
    this.entityId = entityId;
    this.classMeta = classMeta;
    this.idMethod = classMeta.getIdField().getIdMethod();
    this.cacheLoadCallback = cacheLoadCallback;
  }
 
  /**
   * @param selfArg - The proxy object(if you call any method on self, it will result in calling invoke method
   *                   AND that includes a simple toString like if you did log.info("proxy="+self);
   * @param superClassMethod - The method that is on the superclass like Account.java
   * @param subclassProxyMethod - The method that is on the proxy like Account_$$_javassist_0
   */
  @SuppressWarnings("unchecked")
  @Override
  public Object invoke(Object selfArg, Method superClassMethod, Method subclassProxyMethod, Object[] args)
      throws Throwable {
    T self = (T)selfArg;
    if(log.isTraceEnabled()) {
      log.trace("name="+superClassMethod.getName()+"  superClass type="+superClassMethod.getDeclaringClass());
      log.trace("name="+subclassProxyMethod.getName()+" proxy type="+subclassProxyMethod.getDeclaringClass());
    }
   
    //Here we shortcut as we do not need to go to the database...
    if(idMethod.equals(superClassMethod))
      return entityId;
    else if("__markInitializedAndCacheIndexedValues".equals(superClassMethod.getName())) {
      cacheIndexedValues(self);
      isInitialized = true;
      return null;
    } else if("__getOriginalValues".equals(superClassMethod.getName())) {
      return getOriginalValues();
    }
     
   
    //Any other method that is called, toString, getHashCode, getName, someMethod() all end up
    //loading the objects fields from the database in case those methods use those fields
    if(!isInitialized) {
      //If we have a cacheLoadCallback from a List or Map, we are not just loading
      //this entity but the callback method will load this and all other entities from
      //the database in ONE single call instead.
      if(cacheLoadCallback != null) {
        cacheLoadCallback.loadCacheIfNeeded();
      } else {
        fillInThisOneInstance(self);
      }
     
      isInitialized = true;
    }
   
    //Not sure if this should be subclassProxyMethod or superClassMethod
        return subclassProxyMethod.invoke(self, args)// execute the original method.
  }

  private Map<Field, Object> getOriginalValues() {
    return indexFieldToOriginalValue;
  }

  private void cacheIndexedValues(T self) {
    List<MetaField<T>> cols = classMeta.getIndexedColumns();
    for(MetaField<T> f : cols) {
      Field field = f.getField();
      Object value = f.getFieldRawValue(self);
      indexFieldToOriginalValue.put(field, value);
    }
  }

  private void fillInThisOneInstance(T self) {
    MetaIdField<T> idField = classMeta.getIdField();
    Converter converter = idField.getConverter();
    byte[] nonVirtKey = converter.convertToNoSql(entityId);
    DboTableMeta metaDbo = classMeta.getMetaDbo();
    DboColumnIdMeta idMeta = metaDbo.getIdColumnMeta();
    byte[] virtKey = idMeta.formVirtRowKey(nonVirtKey);
   
    List<byte[]> rowKeys = new ArrayList<byte[]>();
    rowKeys.add(virtKey);

    AbstractCursor<KeyValue<Row>> rows = session.find(metaDbo, new IterableWrappingCursor<byte[]>(rowKeys), false, true, null);
    Holder<KeyValue<Row>> holder = rows.nextImpl();
    if(holder == null)
      throw new RowNotFoundException("row for type="+classMeta.getMetaClass().getName()+" not found for key="+entityId);
    KeyValue<Row> next = holder.getValue();
    if(next.getValue() == null)
      throw new RowNotFoundException("row for type="+classMeta.getMetaClass().getName()+" not found for key="+entityId);
   
    Row row = next.getValue();
    classMeta.fillInInstance(row, session, self);
  }

}
TOP

Related Classes of com.alvazan.orm.impl.meta.data.NoSqlProxyImpl

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.