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!
/**
 * Copyright (C) cedarsoft GmbH.
 *
 * Licensed under the GNU General Public License version 3 (the "License")
 * with Classpath Exception; you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *         http://www.cedarsoft.org/gpl3ce
 *         (GPL 3 with Classpath Exception)
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3 only, as
 * published by the Free Software Foundation. cedarsoft GmbH designates this
 * particular file as subject to the "Classpath" exception as provided
 * by cedarsoft GmbH in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 3 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 3 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact cedarsoft GmbH, 72810 Gomaringen, Germany,
 * or visit www.cedarsoft.com if you need additional information or
 * have any questions.
 */

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 javax.annotation.Nonnull;
import javax.annotation.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 {

  @Nonnull
  private static final Log log = LogFactory.getLog( AsynchronousDao.class );

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

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

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

      @Override
      public Object call( @Nonnull 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();
          }
        }
      }
    } );
  }

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

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

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

    return null;
  }

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

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

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

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

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

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

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

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

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

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

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

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

  @Override
  public int getCount() {
    return invoke( new DaoAction() {
      @Override
      public Integer execute( @Nonnull 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
   */
  @Nonnull
  private  R invoke( @Nonnull DaoAction action ) throws AsynchroniousInvocationException {
    return asyncCallSupport.invoke( action );
  }

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

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

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

    /**
     * Execute the action without any return value
     *
     * @param dao the dao
     */
    public abstract void executeVoid( @Nonnull 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( @Nonnull GenericDao dao );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy