Package com.spoledge.audao.db.dao.gae

Source Code of com.spoledge.audao.db.dao.gae.GaeAbstractDaoImpl

/*
* Copyright 2010 Spolecne s.r.o. (www.spoledge.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.spoledge.audao.db.dao.gae;

import java.util.Calendar;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Category;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.Email;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.GeoPt;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.ShortBlob;
import com.google.appengine.api.datastore.Text;
import com.google.appengine.api.datastore.Transaction;

import com.google.appengine.api.users.User;

import static com.google.appengine.api.datastore.FetchOptions.Builder.*;

import com.spoledge.audao.db.dao.DaoException;
import com.spoledge.audao.db.dao.DBException;
import com.spoledge.audao.db.dao.DtoCache;
import com.spoledge.audao.db.dao.DtoCacheFactory;
import com.spoledge.audao.db.dao.ExpiringMemoryDtoCacheImpl;
import com.spoledge.audao.db.dao.RootDaoImpl;


/**
* This is the parent of all DAO implementation classes.
* It uses all common generic methods and utilities.
* The implementation is not thread safe - we assume
* that the client creates one DAO impl per thread.
*/
public abstract class GaeAbstractDaoImpl<T> extends RootDaoImpl {

    private static final String GQL_DYNAMIC_QUERY_IMPL = "com.spoledge.audao.parser.gql.GqlDynamic";
    private static Class<? extends GQLDynamicQuery> GQLDynamicQueryImplClass;


    /**
     * Caching of entities - a short term cache allowing to optimize
     * the calls find + update.
     */
    protected static DtoCache<Key, Entity> entityCache = new ExpiringMemoryDtoCacheImpl<Key, Entity>( 100, 10 );

    /**
     * Caching of entities - a short term cache allowing to optimize
     * the calls find + update.
     */
    protected DtoCache<Key, Entity> txEntityCache;

    /**
     * The last known transaction.
     */
    protected Transaction tx;


    ////////////////////////////////////////////////////////////////////////////
    // Attributes
    ////////////////////////////////////////////////////////////////////////////

    /**
     * The assigned datastore service.
     */
    protected DatastoreService ds;


    /**
     * Flag indicating that "!=" or "IN" operators are used in conditions.
     * THe query must be processed by GQLDynamicQuery.
     */
    protected boolean multipleQueries;


    /**
     * GQLDynamicQuery is used to preocess dynamic queries
     * and static queries containing "!=" or "IN" operators.
     */
    protected GQLDynamicQuery gqlDynamicQuery;


    ////////////////////////////////////////////////////////////////////////////
    // Constructors
    ////////////////////////////////////////////////////////////////////////////

    /**
     * Creates a new DAO implementation.
     * @throws NullPointerException when the passed DS is null.
     */
    protected GaeAbstractDaoImpl( DatastoreService ds ) {
        if (ds == null) {
            throw new NullPointerException("The datastore service is null");
        }

        this.ds = ds;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Public
    ////////////////////////////////////////////////////////////////////////////

    /**
     * Clears entity cache.
     * This method is useful when testing.
     */
    public static void clearEntityCache() {
        entityCache.clear();
    }


    ////////////////////////////////////////////////////////////////////////////
    // Protected
    ////////////////////////////////////////////////////////////////////////////

    /**
     * Finds one record by filled query.
     * @param query the query ready for execution
     * @param cond the SQL/GQL condition used only for logging
     * @param offset the offset of the result set starting at 0
     * @param params the parameters used only for logging
     * @return the record found or null
     */
    protected T findOne( Query query, String cond, int offset, Object... params ) {
        String sql = "SELECT * FROM " + getTableName() + " WHERE " + cond;

        debugSql( sql, params );

        PreparedQuery pq = prepare( query, false );

        try {
            List<Entity> result = pq.asList( getFetchOptions( offset, 1 ));

            return result.size() != 0 ? fetch( result.get( 0 )) : null;
        }
        catch (Exception e) {
            errorSql( e, sql, params );

            handleException( e );

            return null;
        }
    }


    protected T[] findManyArray( Query query, String cond, int offset, int count, Object... params ) {
        return toArray( findManyImpl( query, cond, offset, count, params ));
    }


    protected ArrayList<T> findManyList( Query query, String cond, int offset, int count, Object... params ) {
        return findManyImpl( query, cond, offset, count, params );
    }


    /**
     * Finds more than one record by filled query.
     * @param query the query ready for execution
     * @param cond the SQL/GQL condition used only for logging
     * @param offset the offset of the result set starting at 0
     * @param count the max number of returned records; -1 or Integer.MAX_VALUE mean no limit
     * @param params the parameters used only for logging
     * @return the result list (even empty)
     */
    protected ArrayList<T> findManyImpl( Query query, String cond, int offset, int count, Object[] params ) {
        String sql = "SELECT * FROM " + getTableName() + " WHERE " + cond;

        debugSql( sql, params );

        PreparedQuery pq = prepare( query, false );

        try {
            return fetchList( pq.asIterator( getFetchOptions( offset, count )));
        }
        catch (Exception e) {
            errorSql( e, sql, params );

            handleException( e );

            return null;
        }
    }


    /**
     * Counts records by filled query.
     * @param query the query ready for execution
     * @param cond the SQL/GQL condition used only for logging
     * @param params the parameters used only for logging
     * @return the number of records found
     */
    protected int count( Query query, String cond, Object... params ) {
        String sql = "SELECT count(*) FROM " + getTableName() + " WHERE " + cond;

        debugSql( sql, params );

        PreparedQuery pq = prepare( query, true );

        try {
            return pq.countEntities( withLimit( Integer.MAX_VALUE ));
        }
        catch (Exception e) {
            errorSql( e, sql, params );

            handleException( e );

            return -1;
        }
    }


    /**
     * Deletes a record by filled query.
     * @param query the query ready for execution
     * @param cond the SQL/GQL condition used only for logging
     * @param offset the offset of the result set starting at 0
     * @param count the max number of deleted records; -1 or Integer.MAX_VALUE mean no limit
     * @param params the parameters used only for logging
     * @return true if the record was really deleted
     * @throws DaoException when more than one record was deleted
     */
    protected boolean deleteOne( Query query, String cond, int offset, int count, Object... params )
            throws DaoException {

        int ret = deleteMany( query, cond, offset, count, params );

        if (ret > 1) {
            String err = "More than one record deleted";
            log.error( err + " for " + sqlLog( cond, params ));

            throw new DaoException( err );
        }

        return ret == 1;
    }


    /**
     * Deletes records by filled query.
     * @param query the query ready for execution
     * @param cond the SQL/GQL condition used only for logging
     * @param offset the offset of the result set starting at 0
     * @param count the max number of deleted records; -1 or Integer.MAX_VALUE mean no limit
     * @param params the parameters used only for logging
     * @return the number of deleted records
     */
    protected int deleteMany( Query query, String cond, int offset, int count, Object... params)
            throws DaoException {

        String sql = "DELETE FROM " + getTableName() + " WHERE " + cond;

        debugSql( sql, params );

        PreparedQuery pq = prepare( query, true );

        entityDelete( keyIterable( pq.asIterable( getFetchOptions( offset, count ))));

        return iteratorCount;
    }


    ////////////////////////////////////////////////////////////////////////////
    // Fetch and convert methods
    ////////////////////////////////////////////////////////////////////////////

    /**
     * Fetches data from generic entity into typesafe DTO.
     * @param ent the source generic entity
     * @return the typesafe DTO
     */
    protected T fetch( Entity ent ) {
        return fetch( null, ent );
    }


    /**
     * Fetches data from generic entity into typesafe DTO.
     * @param dto the typesafe DTO which is filled and returned; can be null
     * @param ent the source generic entity
     * @return the typesafe DTO
     */
    protected abstract T fetch( T dto, Entity ent );


    /**
     * Fetches data from generic entities into typesafe DTOs.
     */
    protected T[] fetchArray( Iterator<Entity> iterator ) {
        return toArray( fetchList( iterator ));
    }


    /**
     * Fetches data from generic entities into typesafe DTOs.
     */
    protected ArrayList<T> fetchList( Iterator<Entity> iterator ) {
        ArrayList<T> list = new ArrayList<T>();

        while (iterator.hasNext()) {
            list.add( fetch( null, iterator.next()));
        }

        return list;
    }


    /**
     * Converts list to array.
     */
    protected abstract T[] toArray( ArrayList<T> list );


    ////////////////////////////////////////////////////////////////////////////
    // Datastore R/W
    ////////////////////////////////////////////////////////////////////////////

    /**
     * Reads entity from datastore by its key.
     */
    protected Entity entityGet( Key key ) {
        debugSql( "get", key );

        DtoCache<Key, Entity> cache = getEntityCache();
        Entity ret = cache.get( key );

        if (ret != null) {
            if (log.isDebugEnabled()) {
                log.debug("entityGet(): entity found in cache by key: " + key );
            }

            return ret;
        }

        try {
            ret = ds.get( key );
        }
        catch (EntityNotFoundException e) {
            if (log.isDebugEnabled()) {
                log.debug("entityGet(): entity not found by key: " + key);
            }

            return null;
        }
        catch (Exception e) {
            log.error("entityGet(): key=" + key, e);

            handleException( e );

            return null;
        }

        if (cache != entityCache) entityCache.remove( key );
        cache.put( key, ret );

        return ret;
    }


    /**
     * Writes entity to datastore.
     * @param ent the entity to be written
     * @param dto the dto used only for logging; also can be a simple parameter
     * @param operation the operation (insert/update) used only for logging
     */
    protected Key entityPut( Entity ent, Object dto, String operation ) throws DaoException {
        debugSql( operation, dto );

        Key ret = null;

        try {
            ret = ds.put( ent );
        }
        catch (ConcurrentModificationException e) {
            errorSql( e, operation, dto );

            throw new DaoException("Concurrent transaction detected on entity key=" + ent.getKey());
        }
        catch (Exception e) {
            errorSql( e, operation, dto );

            handleException( e );

            return null;
        }

        DtoCache<Key, Entity> cache = getEntityCache();
        if (cache != entityCache) entityCache.remove( ret );
        cache.put( ret, ent );

        return ret;
    }


    /**
     * Writes several entities to datastore.
     * @param ents the entities to be written
     * @param dtos the dtos used only for logging
     * @param operation the operation (insert/update) used only for logging
     */
    protected List<Key> entityPut( Iterable<Entity> ents, Iterable<?> dtos, String operation )
            throws DaoException {

        debugSql( operation, dtos );

        List<Key> ret = null;

        try {
            ret = ds.put( ents );
        }
        catch (ConcurrentModificationException e) {
            errorSql( e, operation, dtos );

            throw new DaoException("Concurrent transaction detected on entities");
        }
        catch (Exception e) {
            errorSql( e, operation, dtos );

            handleException( e );

            return null;
        }

        // no entity cache handling - should manually clear it if necessary.

        return ret;
    }


    /**
     * Removes entity from datastore.
     * @return true if the entity was really deleted
     */
    protected boolean entityDelete( Key key ) throws DaoException {
        try {
            ds.delete( key );
        }
        catch (ConcurrentModificationException e) {
            log.error("entityDelete():" + e + ", key=" + key );

            throw new DaoException("Concurrent transaction detected on entity key=" + key);
        }
        catch (IllegalArgumentException e) {
            log.warn("entityDelete():" + e + ", key=" + key );

            return false;
        }
        catch (Exception e) {
            log.error("entityDelete(): key=" + key, e);

            handleException( e );

            return false;
        }

        entityCache.remove( key );
        if (txEntityCache != null) txEntityCache.remove( key );

        return true;
    }


    /**
     * Removes entities from datastore.
     */
    protected void entityDelete( Iterable<Key> keys ) throws DaoException {
        try {
            ds.delete( keys );
        }
        catch (ConcurrentModificationException e) {
            log.error("entityDelete():" + e);

            throw new DaoException("Concurrent transaction detected on entities");
        }
        catch (Exception e) {
            log.error("entityDelete():", e);

            handleException( e );

            return;
        }

        for (Key key : keys) entityCache.remove( key );
        if (txEntityCache != null) {
            for (Key key : keys) txEntityCache.remove( key );
        }
    }


    /**
     * Prepares query.
     */
    protected PreparedQuery prepare( Query query ) {
        return prepare( query, false );
    }


    /**
     * Prepares query.
     */
    protected PreparedQuery prepare( Query query, boolean keysOnly ) {
        try {
            if (multipleQueries) {
                return getGQLDynamicQuery().prepareMultipleQueries( query, keysOnly );
            }
            else {
                if (keysOnly) query.setKeysOnly();

                return ds.prepare( query.getAncestor() != null ? ds.getCurrentTransaction( null ) : null, query );
            }
        }
        catch (Exception e) {
            log.error("prepare(): query=" + query, e);

            handleException( e );

            return null;
        }
    }


    ////////////////////////////////////////////////////////////////////////////
    // Conversion methods Entity to DTO
    ////////////////////////////////////////////////////////////////////////////

    protected Boolean getBoolean( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Boolean) return ((Boolean)o);

        String s = o.toString().trim();

        if ("true".equals( s )) return true;
        if ("false".equals( s )) return false;

        invalidType( ent, prop, Boolean.class );
        return null;
    }


    protected Short getShort( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Number) return ((Number)o).shortValue();

        try {
            return new Short( o.toString().trim());
        }
        catch (NumberFormatException e) {}

        invalidType( ent, prop, Short.class );
        return null;
    }


    protected Integer getInteger( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Number) return ((Number)o).intValue();

        try {
            return new Integer( o.toString().trim());
        }
        catch (NumberFormatException e) {}

        invalidType( ent, prop, Integer.class );
        return null;
    }


    protected Long getLong( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Number) return ((Number)o).longValue();

        try {
            return new Long( o.toString().trim());
        }
        catch (NumberFormatException e) {}

        invalidType( ent, prop, Long.class );
        return null;
    }


    protected Double getDouble( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Number) return ((Number)o).doubleValue();

        try {
            return new Double( o.toString().trim());
        }
        catch (NumberFormatException e) {}

        invalidType( ent, prop, Double.class );
        return null;
    }


    protected String getString( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof String) return ((String)o);
        if (o instanceof Text) return ((Text)o).getValue();
        if (o instanceof Category) return ((Category)o).getCategory();
        if (o instanceof Email) return ((Email)o).getEmail();

        return o.toString();
    }


    protected java.sql.Date getDate( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof java.sql.Date) return ((java.sql.Date)o);
        if (o instanceof java.util.Date) return new java.sql.Date(((java.util.Date)o).getTime());
        if (o instanceof Number) return new java.sql.Date(((Number)o).longValue());

        invalidType( ent, prop, java.sql.Date.class );
        return null;
    }


    protected java.sql.Timestamp getTimestamp( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof java.sql.Timestamp) return ((java.sql.Timestamp)o);
        if (o instanceof java.util.Date) return new java.sql.Timestamp(((java.util.Date)o).getTime());
        if (o instanceof Number) return new java.sql.Timestamp(((Number)o).longValue());

        invalidType( ent, prop, java.sql.Timestamp.class );
        return null;
    }


    protected byte[] getByteArray( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Blob) return ((Blob)o).getBytes();
        if (o instanceof ShortBlob) return ((ShortBlob)o).getBytes();

        invalidType( ent, prop, Blob.class );
        return null;
    }


    protected <S> S getObject( Entity ent, String prop, Class<S> clazz ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof Blob) return deserialize(((Blob)o).getBytes(), clazz);
        if (o instanceof ShortBlob) return deserialize(((ShortBlob)o).getBytes(), clazz);

        invalidType( ent, prop, Blob.class );
        return null;
    }


    protected <S> S getCoreObject( Entity ent, String prop, Class<S> clazz ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        try {
            return clazz.cast( o );
        }
        catch (Exception e) {}

        if (o instanceof Blob) return deserialize(((Blob)o).getBytes(), clazz);
        if (o instanceof ShortBlob) return deserialize(((ShortBlob)o).getBytes(), clazz);
        if (clazz == String.class && (o instanceof Text)) return clazz.cast(((Text)o).getValue());

        invalidType( ent, prop, clazz );
        return null;
    }


    /**
     * Returns native list - as fetched by GAE API.
     */
    @SuppressWarnings("unchecked")
    protected <S> List<S> getList( Entity ent, String prop ) {
        Object o = ent.getProperty( prop );
        if (o == null) return null;

        if (o instanceof List) {
            return (List<S>) o;
        }

        invalidType( ent, prop, List.class );
        return null;
    }


    /**
     * Returns native list - as fetched by GAE API.
     */
    protected <S> List<S> getList( Entity ent, String prop, Class<S> clazz ) {
        return getList( ent, prop );
    }


    /**
     * Returns list of deserialized object.
     */
    @SuppressWarnings("unchecked")
    protected <S> List<S> getListOfObjects( Entity ent, String prop ) {
        List<S> list = getList( ent, prop );

        if ( list == null ) return null;

        ArrayList ret = new ArrayList( list.size());

        for ( Object o : list ) {
            if (o == null) ret.add( null );
            else if (o instanceof Blobret.add( deserialize(((Blob)o).getBytes(), Object.class ));
            else if (o instanceof ShortBlob) ret.add( deserialize(((ShortBlob)o).getBytes(), Object.class ));
            else ret.add( o );
        }

        return ret;
    }


    /**
     * Returns list of deserialized object.
     */
    protected <S> List<S> getListOfObjects( Entity ent, String prop, Class<S> clazz ) {
        List<S> list = getList( ent, prop, clazz );

        if ( list == null ) return null;

        ArrayList<S> ret = new ArrayList<S>( list.size());

        for ( Object o : list ) {
            if (o == null) ret.add( null );
            else if (o instanceof Blobret.add( deserialize(((Blob)o).getBytes(), clazz ));
            else if (o instanceof ShortBlob) ret.add( deserialize(((ShortBlob)o).getBytes(), clazz ));
            else {
                try {
                    ret.add( clazz.cast( o ));
                }
                catch (Exception e) {
                    invalidType( ent, prop, clazz );
                }
            }
        }

        return ret;
    }


    protected void invalidType( Entity ent, String prop, Class<?> expected ) {
        Object o = ent.getProperty( prop );
        Class<?> actual = o.getClass();

        log.error("invalidType(): kind=" + ent.getKind() + ", prop=" + prop + ", key=" + ent.getKey()
                    + ", expected=" + expected + ", found=" + actual + ", value=" + o );

        throw new RuntimeException("Invalid property type of property " + ent.getKind() + '.' + prop );
    }


    ////////////////////////////////////////////////////////////////////////////
    // Conversion methods DTO to Entity
    ////////////////////////////////////////////////////////////////////////////

    protected java.util.Date date( int year, int month, int day ) {
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set( Calendar.YEAR, year );
        cal.set( Calendar.MONTH, month - 1 );
        cal.set( Calendar.DAY_OF_MONTH, day );

        return cal.getTime();
    }


    protected java.util.Date datetime( int year, int month, int day, int hour, int min, int sec ) {
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set( Calendar.YEAR, year );
        cal.set( Calendar.MONTH, month - 1 );
        cal.set( Calendar.DAY_OF_MONTH, day );
        cal.set( Calendar.HOUR_OF_DAY, hour );
        cal.set( Calendar.MINUTE, min );
        cal.set( Calendar.SECOND, sec );

        return cal.getTime();
    }


    protected java.util.Date time( int hour, int min, int sec ) {
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set( Calendar.HOUR_OF_DAY, hour );
        cal.set( Calendar.MINUTE, min );
        cal.set( Calendar.SECOND, sec );

        return cal.getTime();
    }


    /**
     * This method crops time to emulate same behavior as JDBC drivers.
     */
    protected java.util.Date date( java.sql.Date val ) {
        if (val == null) return null;

        Calendar cal = Calendar.getInstance();
        cal.setTime( val );
        cal.set( Calendar.HOUR_OF_DAY, 0 );
        cal.set( Calendar.MINUTE, 0 );
        cal.set( Calendar.SECOND, 0 );
        cal.set( Calendar.MILLISECOND, 0 );

        return cal.getTime();
    }


    protected java.util.Date date( java.sql.Timestamp val ) {
        return val != null ? new java.util.Date( val.getTime()) : null;
    }


    protected Blob blob( byte[] val ) {
        return val != null ? new Blob( val ) : null;
    }


    protected Blob blob( Object val ) {
        return val != null ? new Blob( serialize( val )) : null;
    }


    protected ShortBlob shortBlob( byte[] val ) {
        return val != null ? new ShortBlob( val ) : null;
    }


    protected ShortBlob shortBlob( Object val ) {
        return val != null ? new ShortBlob( serialize( val )) : null;
    }


    protected GeoPt geopt( Number latitude, Number longitude ) {
        return latitude != null && longitude != null ?
            new GeoPt( latitude.floatValue(), longitude.floatValue()) : null;
    }


    protected User user( String email ) {
        return email != null ? new User( email, "gmail.com" ) : null;
    }


    protected List<Blob> blobs( List list ) {
        if ( list == null ) return null;

        ArrayList<Blob> ret = new ArrayList<Blob>( list.size());

        for ( Object o : list ) {
            ret.add( blob( o ));
        }

        return ret;
    }


    protected List<ShortBlob> shortBlobs( List list ) {
        if ( list == null ) return null;

        ArrayList<ShortBlob> ret = new ArrayList<ShortBlob>( list.size());

        for ( Object o : list ) {
            ret.add( shortBlob( o ));
        }

        return ret;
    }


    protected List<ShortBlob> shortBlobsOfByteArray( List<byte[]> list ) {
        if ( list == null ) return null;

        ArrayList<ShortBlob> ret = new ArrayList<ShortBlob>( list.size());

        for ( byte[] o : list ) {
            ret.add( shortBlob( o ));
        }

        return ret;
    }


    protected List<java.util.Date> datesOfDate( List<? extends java.sql.Date> list ) {
        if ( list == null ) return null;

        ArrayList<java.util.Date> ret = new ArrayList<java.util.Date>( list.size());

        for ( java.sql.Date o : list ) {
            ret.add( date( o ));
        }

        return ret;
    }


    protected List<java.util.Date> datesOfTimestamp( List<? extends java.sql.Timestamp> list ) {
        if ( list == null ) return null;

        ArrayList<java.util.Date> ret = new ArrayList<java.util.Date>( list.size());

        for ( java.sql.Timestamp o : list ) {
            ret.add( date( o ));
        }

        return ret;
    }


    protected List<Integer> ordinals( List<? extends Enum> list ) {
        if ( list == null ) return null;

        ArrayList<Integer> ret = new ArrayList<Integer>( list.size());

        for ( Enum o : list ) {
            ret.add( o.ordinal() + 1 );
        }

        return ret;
    }


    protected List<String> names( List<? extends Enum> list ) {
        if ( list == null ) return null;

        ArrayList<String> ret = new ArrayList<String>( list.size());

        for ( Enum o : list ) {
            ret.add( o.name());
        }

        return ret;
    }


    ////////////////////////////////////////////////////////////////////////////
    // Utilities
    ////////////////////////////////////////////////////////////////////////////

    protected void handleException( Exception e ) {
        throw new DBException( e );
    }


    protected Query getQueryCond( String cond, Object...params ) {
        return getQueryCond( (Query) null, cond, params );
    }


    protected Query getQueryCond( Query q, String cond, Object...params ) {
        if (q == null) q = getQuery();

        if ( cond != null && cond.length() > 0 ) {
            GQLDynamicQuery gql = getGQLDynamicQuery();
            q = gql.parseQueryCond( q, cond, params );

            multipleQueries = gql.wasMultipleQueries();
        }

        return q;
    }


    protected Query getQuery() {
        return new Query( getTableName());
    }


    protected Key key( long id ) {
        return key( getTableName(), id );
    }


    protected Key key( String name ) {
        return key( getTableName(), name );
    }


    protected Key key( String kind, long id ) {
        return KeyFactory.createKey( kind, id );
    }


    protected Key key( String kind, String name ) {
        return KeyFactory.createKey( kind, name );
    }


    protected Key key( Key parent, String kind, long id ) {
        return KeyFactory.createKey( parent, kind, id );
    }


    protected Key key( Key parent, String kind, String name ) {
        return KeyFactory.createKey( parent, kind, name );
    }


    protected Key parentKey( Key key ) {
        return parentKey( key, 1 );
    }


    protected Key parentKey( Key key, int depth ) {
        while ( depth-- > 0 ) {
            if (key == null) return null;
            key = key.getParent();
        }

        return key;
    }


    protected Long parentKeyAsLong( Key key, int depth ) {
        Key ret = parentKey( key, depth );

        return ret != null ? ret.getId() : null;
    }


    protected String parentKeyAsString( Key key, int depth ) {
        Key ret = parentKey( key, depth );

        return ret != null ? ret.getName() : null;
    }


    protected Iterable<Key> keyIterable( final Iterable<Entity> ie ) {
        return new Iterable<Key>() {
            public Iterator<Key> iterator() {
                return keyIterator( ie.iterator());
            }
        };
    }


    protected int iteratorCount;

    protected Iterator<Key> keyIterator( final Iterator<Entity> ie ) {
        iteratorCount = 0;

        return new Iterator<Key>() {
            public boolean hasNext() {
                return ie.hasNext();
            }

            public Key next() {
                iteratorCount++;

                return ie.next().getKey();
            }

            public void remove() {
                ie.remove();
            }
        };
    }


    protected FetchOptions getFetchOptions( int offset, int count ) {
        FetchOptions fo = withOffset( offset );

        if (isLimit( count )) {
            fo = fo.limit( count );
        }

        return fo;
    }


    protected boolean isLimit( int count ) {
        return count >= 0 && count != Integer.MAX_VALUE;
    }


    protected GQLDynamicQuery getGQLDynamicQuery() {
        if (gqlDynamicQuery == null) {
            try {
                if (GQLDynamicQueryImplClass == null) {
                    GQLDynamicQueryImplClass = Class.forName( GQL_DYNAMIC_QUERY_IMPL )
                                                    .asSubclass( GQLDynamicQuery.class );
                }

                gqlDynamicQuery = GQLDynamicQueryImplClass.newInstance();
                gqlDynamicQuery.setDatastoreService( ds );
            }
            catch (Exception e) {
                log.error("getGQLDynamicQuery(): cannot instantiate dynamic GQL parser: ", e );

                throw new RuntimeException( e );
            }
        }

        return gqlDynamicQuery;
    }


    protected DtoCache<Key, Entity> getEntityCache() {
        Transaction currentTx = ds.getCurrentTransaction( null );

        if (currentTx == null) {
            if (tx != null) {
                tx = null;
                txEntityCache.clear();
            }

            return entityCache;
        }
        else {
            if (txEntityCache == null) {
                txEntityCache = new ExpiringMemoryDtoCacheImpl<Key, Entity>( 100, 10 );
                tx = currentTx;
            }
            else if (tx != currentTx) {
                txEntityCache.clear();
                tx = currentTx;
            }

            return txEntityCache;
        }
    }
}
TOP

Related Classes of com.spoledge.audao.db.dao.gae.GaeAbstractDaoImpl

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.