
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 extends T> findAll() {
return invoke( new DaoAction>() {
@Override
public List extends T> 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