All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cedarsoft.gdao.async.AsynchronousDao Maven / Gradle / Ivy

The newest version!
package com.cedarsoft.gdao.async;

import com.cedarsoft.async.AsyncCallSupport;
import com.cedarsoft.async.AsynchroniousInvocationException;
import com.cedarsoft.async.CallbackCaller;
import com.cedarsoft.gdao.AbstractGenericDao;
import com.cedarsoft.gdao.Finder;
import com.cedarsoft.gdao.GenericDao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fest.reflect.core.Reflection;
import org.fest.reflect.exception.ReflectionError;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.concurrent.locks.Lock;

/**
 * An asynchronous dao where the save/loading is done in another thread.
 * You have to call {@link #initializeDelegatingDao(GenericDao, Lock)} to start the
 * worker threads.
 */
public class AsynchronousDao extends AbstractGenericDao {
  @NonNls
  @NotNull
  private static final Log log = LogFactory.getLog( AsynchronousDao.class );

  @NotNull
  protected final AsyncCallSupport> asyncCallSupport = new AsyncCallSupport>();

  /**
   * Initializes the delegating dao with a null lock
   *
   * @param delegatingDao the delegating dao
   */
  public void initializeDelegatingDao( @NotNull final GenericDao delegatingDao ) {
    initializeDelegatingDao( delegatingDao, null );
  }

  /**
   * Sets the backing dao and start the worker thread
   *
   * @param delegatingDao the delegating dao
   * @parramt lock the lock that is used before the callback is executed
   */
  public void initializeDelegatingDao( @NotNull final GenericDao delegatingDao, @Nullable final Lock lock ) {
    log.info( "initializing with " + delegatingDao );
    asyncCallSupport.initializeWorker( new CallbackCaller>() {
      @NotNull
      public String getDescription() {
        return "AsynchroniousDao-CallbackCaller for " + delegatingDao;
      }

      public Object call( @NotNull DaoAction callback ) throws Exception {
        log.debug( "executing " + callback );
        if ( lock != null ) {
          //noinspection LockAcquiredButNotSafelyReleased
          lock.lock();
        }
        try {
          return callback.execute( delegatingDao );
        } finally {
          if ( lock != null ) {
            lock.unlock();
          }
        }
      }
    } );
  }

  @NotNull
  public  Long save( @NotNull final LT newInstance ) {
    return invoke( new DaoAction() {
      @NotNull
      public Long execute( @NotNull GenericDao dao ) {
        return dao.save( newInstance );
      }

      @Override
      public String toString() {
        return "saving " + newInstance.getClass().getName() + ": " + newInstance + " with id " + resolveId( newInstance );
      }
    } );
  }

  @Nullable
  protected Object resolveId( @NotNull Object object ) {
    try {
      return Reflection.field( "id" ).ofType( Long.class ).in( object ).get();
    } catch ( ReflectionError ignore ) {
      ignore.printStackTrace();
    }

    return null;
  }

  public  void update( @NotNull final LT transientObject ) {
    invokeVoid( new VoidDaoAction() {
      @Override
      public void executeVoid( @NotNull GenericDao dao ) {
        dao.update( transientObject );
      }

      @Override
      public String toString() {
        return "Updating " + transientObject.getClass().getName() + ": " + transientObject + " with id " + resolveId( transientObject );
      }
    } );
  }

  public  void saveOrUpdate( @NotNull final LT object ) {
    invokeVoid( new VoidDaoAction() {
      @Override
      public void executeVoid( @NotNull GenericDao dao ) {
        dao.saveOrUpdate( object );
      }

      @Override
      public String toString() {
        return "SaveOrUpdate " + object.getClass().getName() + ": " + object + " with id " + resolveId( object );
      }
    } );
  }

  public  void delete( @NotNull final LT persistentObject ) {
    invokeVoid( new VoidDaoAction() {
      @Override
      public void executeVoid( @NotNull GenericDao dao ) {
        dao.delete( persistentObject );
      }

      @Override
      public String toString() {
        return "Deleting " + persistentObject.getClass().getName() + " " + persistentObject + " with id " + resolveId( persistentObject );
      }
    } );
  }

  @NotNull
  public T findById( @NotNull final Long id ) {
    return invoke( new DaoAction() {
      @NotNull
      public T execute( @NotNull GenericDao dao ) {
        return dao.findById( id );
      }

      @Override
      public String toString() {
        return "findById " + id;
      }
    } );
  }

  @NotNull
  public  R find( @NotNull final Finder finder ) {
    return invoke( new DaoAction() {
      @NotNull
      public R execute( @NotNull GenericDao dao ) {
        return dao.find( finder );
      }

      @Override
      public String toString() {
        return "find with " + finder;
      }
    } );
  }

  @NotNull
  public List findAll() {
    return invoke( new DaoAction>() {
      public List execute( @NotNull GenericDao dao ) {
        return dao.findAll();
      }

      @Override
      public String toString() {
        return "finding All";
      }
    } );
  }

  public int getCount() {
    return invoke( new DaoAction() {
      public Integer execute( @NotNull GenericDao dao ) {
        return dao.getCount();
      }

      @Override
      public String toString() {
        return "getting count";
      }
    } );
  }

  /**
   * Invokes an action
   *
   * @param action the action
   * @return the return value of the action
   */
  @NotNull
  private  R invoke( @NotNull DaoAction action ) throws AsynchroniousInvocationException {
    return asyncCallSupport.invoke( action );
  }

  /**
   * Invokes an action
   *
   * @param actionVoid the action
   * @throws AsynchroniousInvocationException
   *
   */
  private void invokeVoid( @NotNull VoidDaoAction actionVoid ) throws AsynchroniousInvocationException {
    asyncCallSupport.invokeVoid( actionVoid );
  }

  public void shutdown() {
    asyncCallSupport.shutdown();
  }

  /**
   * A action that doesn't have a return value
   */
  public abstract static class VoidDaoAction implements DaoAction {
    @Nullable
    public Object execute( @NotNull GenericDao dao ) {
      executeVoid( dao );
      return null;
    }

    /**
     * Execute the action without any return value
     *
     * @param dao the dao
     */
    public abstract void executeVoid( @NotNull GenericDao dao );
  }

  /**
   * An action that has an return value
   */
  public static interface DaoAction {
    /**
     * Executes the action
     *
     * @param dao the dao
     * @return the return value
     */
    @Nullable
    R execute( @NotNull GenericDao dao );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy