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

act.db.ebean2.EbeanDao Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
package act.db.ebean2;

/*-
 * #%L
 * ACT AAA Plugin
 * %%
 * Copyright (C) 2015 - 2017 ActFramework
 * %%
 * 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.
 * #L%
 */

import static act.Act.app;

import act.app.DbServiceManager;
import act.db.*;
import act.db.Model;
import act.inject.param.NoBind;
import act.util.General;
import io.ebean.*;
import io.ebeaninternal.api.SpiEbeanServer;
import org.osgl.$;
import org.osgl.logging.L;
import org.osgl.logging.Logger;
import org.osgl.util.C;
import org.osgl.util.E;
import org.osgl.util.S;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.persistence.Id;
import javax.sql.DataSource;

@General
@NoBind
public class EbeanDao extends DaoBase> {

    private static final Logger logger = L.get(EbeanDao.class);

    private volatile EbeanServer ebean;
    private volatile DataSource ds;
    private String tableName;
    private Field idField = null;
    private List queryIterators = C.newList();

    EbeanDao(EbeanService service) {
        init(modelType());
        this.ebean(service.ebean());
    }

    EbeanDao(Class idType, Class modelType, EbeanService service) {
        super(idType, modelType);
        init(modelType);
        this.setEbean(service.ebean());
        this.ds = service.dataSource();
    }

    public EbeanDao(Class id_type, Class modelType) {
        super(id_type, modelType);
        init(modelType);
    }

    public EbeanDao() {
        init(modelType());
    }

    public void ebean(EbeanServer ebean) {
        setEbean($.notNull(ebean));
    }

    public void modelType(Class type) {
        this.modelType = $.cast(type);
    }

    @Override
    protected void releaseResources() {
        if (null != queryIterators) {
            for (QueryIterator i : queryIterators) {
                try {
                    i.close();
                } catch (Exception e) {
                    logger.warn(e, "error closing query iterators");
                }
            }
            queryIterators.clear();
            queryIterators = null;
        }
    }

    private void init(Class modelType) {
        for (Field f: modelType.getDeclaredFields()) {
            Id idAnno = f.getAnnotation(Id.class);
            if (null != idAnno) {
                idField = f;
                f.setAccessible(true);
                break;
            }
        }
    }

    private void setEbean(EbeanServer ebean) {
        this.ebean = ebean;
        this.tableName = ((SpiEbeanServer) ebean).getBeanDescriptor(modelType()).getBaseTable();
    }

    private EbeanService getService(String dbId, DbServiceManager mgr) {
        DbService svc = mgr.dbService(dbId);
        E.invalidConfigurationIf(null == svc, "Cannot find db service by id: %s", dbId);
        E.invalidConfigurationIf(!(svc instanceof EbeanService), "The db service[%s|%s] is not ebean service", dbId, svc.getClass());
        return $.cast(svc);
    }

    public EbeanServer ebean() {
        if (null != ebean) {
            return ebean;
        }
        synchronized (this) {
            if (null == ebean) {
                DB db = modelType().getAnnotation(DB.class);
                String dbId = null == db ? DbServiceManager.DEFAULT : db.value();
                EbeanService dbService = getService(dbId, app().dbServiceManager());
                E.NPE(dbService);
                setEbean(dbService.ebean());
            }
        }
        return ebean;
    }

    public DataSource ds() {
        if (null != ds) {
            return ds;
        }
        synchronized (this) {
            if (null == ds) {
                DB db = modelType().getAnnotation(DB.class);
                String dbId = null == db ? DbServiceManager.DEFAULT : db.value();
                EbeanService dbService = getService(dbId, app().dbServiceManager());
                E.NPE(dbService);
                ds = dbService.dataSource();
            }
        }
        return ds;
    }

    void registerQueryIterator(QueryIterator i) {
        queryIterators.add(i);
    }

    @Override
    public MODEL_TYPE findById(ID_TYPE id) {
        return ebean().find(modelType(), id);
    }

    @Override
    public MODEL_TYPE findLatest() {
        throw E.unsupport();
    }

    @Override
    public MODEL_TYPE findLastModified() {
        throw E.unsupport();
    }

    @Override
    public Iterable findBy(String fields, Object... values) throws IllegalArgumentException {
        EbeanQuery q = q(fields, values);
        return q.fetch();
    }

    @Override
    public Iterable findByIdList(Collection idList) {
        EbeanQuery q = q();
        q.where().idIn(C.list(idList));
        return q.fetch();
    }

    @Override
    public MODEL_TYPE findOneBy(String fields, Object... values) throws IllegalArgumentException {
        EbeanQuery q = q(fields, values);
        return q.first();
    }

    @Override
    public Iterable findAll() {
        return q().fetch();
    }

    @Override
    public List findAllAsList() {
        return q().findList();
    }

    @Override
    public MODEL_TYPE reload(MODEL_TYPE entity) {
        ebean().refresh(entity);
        return entity;
    }

    @Override
    public ID_TYPE getId(MODEL_TYPE entity) {
        if (entity instanceof Model) {
            return (ID_TYPE) ((Model) entity)._id();
        } else if (null != idField) {
            try {
                return (ID_TYPE) idField.get(entity);
            } catch (IllegalAccessException e) {
                throw E.unexpected(e);
            }
        } else {
            return null;
        }
    }

    @Override
    public long count() {
        return q().findCount();
    }

    @Override
    public long countBy(String fields, Object... values) throws IllegalArgumentException {
        EbeanQuery q = q(fields, values);
        return q.count();
    }

    @Override
    public MODEL_TYPE save(MODEL_TYPE entity) {
        ebean().save(entity);
        return entity;
    }

    public MODEL_TYPE save(Transaction tx, MODEL_TYPE entity) {
        ebean().save(entity, tx);
        return entity;
    }

    @Override
    public List save(Iterable iterable) {
        List list = C.list(iterable);
        if (list.isEmpty()) {
            return list;
        }
        ebean().saveAll(list);
        return list;
    }

    public List save(Transaction tx, Iterable iterable) {
        List list = C.list(iterable);
        ebean().saveAll(list, tx);
        return list;
    }

    @Override
    public void save(MODEL_TYPE entity, String fields, Object... values) throws IllegalArgumentException {
        ebean().update(entity);
    }

    public void save(Transaction tx, MODEL_TYPE entity, String fields, Object... values) throws IllegalArgumentException {
        ebean().update(entity, tx);
    }

    @Override
    public void delete(MODEL_TYPE entity) {
        ebean().delete(entity);
    }

    public void delete(Transaction tx, MODEL_TYPE entity) {
        ebean().delete(entity, tx);
    }

    @Override
    public void delete(EbeanQuery query) {
        ebean().delete(query.rawQuery(), null);
    }

    public void delete(Transaction tx, EbeanQuery query) {
        ebean().delete(query.rawQuery(), tx);
    }

    @Override
    public void deleteById(ID_TYPE id) {
        ebean().delete(modelType(), id);
    }

    public void deleteById(Transaction tx, ID_TYPE id) {
        ebean().delete(modelType(), id, tx);
    }

    @Override
    public void deleteBy(String fields, Object... values) throws IllegalArgumentException {
        delete(q(fields, values));
    }

    public void deleteBy(Transaction tx, String fields, Object... values) throws IllegalArgumentException {
        delete(tx, q(fields, values));
    }

    @Override
    public void deleteAll() {
        delete(q());
    }

    public void deleteAll(Transaction tx) {
        delete(tx, q());
    }

    @Override
    public void drop() {
        String sql = "DELETE from " + tableName;
        SqlUpdate sqlUpdate = ebean().createSqlUpdate(sql);
        ebean().execute(sqlUpdate);
    }

    @Override
    public EbeanQuery q() {
        return new EbeanQuery(this, modelType());
    }

    @Override
    public EbeanQuery createQuery() {
        return q();
    }

    boolean ebeanServerProvided() {
        return null != ebean;
    }

    private enum R2 {
        betweenProperties() {
            @Override
            void applyTo(ExpressionList where, String field1, String field2, Object val) {
                where.betweenProperties(field1, field2, val);
            }
        },
        bp() {
            @Override
            void applyTo(ExpressionList where, String field1, String field2, Object val) {
                where.betweenProperties(field1, field2, val);
            }
        };
        abstract void applyTo(ExpressionList where, String field1, String field2, Object val);
    }

    public static final String ID = "_id";

    private enum R1 {
        eq() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                if (ID.equals(field)) {
                    where.idEq(val);
                    return;
                }
                if (null == val) {
                    where.isNull(field);
                } else {
                    where.eq(field, val);
                }
            }
        }, ne() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.ne(field, val);
            }
        }, ieq() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.ieq(field, val.toString());
            }
        }, between() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                if (val instanceof $.T2) {
                    $.T2 t2 = $.cast(val);
                    where.between(field, t2._1, t2._2);
                } else if (val.getClass().isArray()) {
                    int len = Array.getLength(val);
                    if (len != 2) {
                        throw E.unexpected(" value array length is not correct, expected: 2; found: %s", len);
                    }
                    where.between(field, Array.get(val, 0), Array.get(val, 1));
                } else if (val instanceof Collection) {
                    int len = ((Collection) val).size();
                    if (len != 2) {
                        throw E.unexpected(" value collection size is not correct, expected: 2; found: %s", len);
                    }
                    Iterator itr = ((Collection) val).iterator();
                    where.between(field, itr.next(), itr.next());
                } else {
                    throw E.unexpected(" value type not recognized: %s", val.getClass());
                }
            }
        }, gt() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.gt(field, val);
            }
        }, ge() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.ge(field, val);
            }
        }, lt() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.lt(field, val);
            }
        }, le() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.le(field, val);
            }
        }, isNull() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                // val is not relevant here
                where.isNull(field);
            }
        }, isNotNull() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                // val is not relevant here
                where.isNotNull(field);
            }
        }, like() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                String s = S.string(val);
                if (!s.contains("%")) {
                    s = S.builder("%").append(s).append("%").toString();
                }
                where.like(field, s);
            }
        }, ilike() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                String s = S.string(val);
                if (!s.contains("%")) {
                    s = S.builder("%").append(s).append("%").toString();
                }
                where.ilike(field, s);
            }
        }, startsWith() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.startsWith(field, val.toString());
            }
        }, istartsWith() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.istartsWith(field, val.toString());
            }
        }, endsWith() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.endsWith(field, val.toString());
            }
        }, contains() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.contains(field, val.toString());
            }
        }, icontains() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                where.icontains(field, val.toString());
            }
        }, in() {
            @Override
            void applyTo(ExpressionList where, String field, Object val) {
                E.NPE(field, val);
                if (val instanceof Query) {
                    where.in(field, (Query)val);
                } else if (val instanceof Collection) {
                    if (ID.equals(field)) {
                        where.idIn(C.list((Collection)val));
                    } else {
                        where.in(field, (Collection) val);
                    }
                } else if (val.getClass().isArray()) {
                    int len = Array.getLength(val);
                    if (len == 0) {
                        if (ID.equals(field)) {
                            where.idIn(C.list());
                        } else {
                            where.in(field, new Object[0]);
                        }
                    } else {
                        Object[] array = new Object[len];
                        for (int i = 0; i < len; ++i) {
                            array[i] = Array.get(val, i);
                        }
                        if (ID.equals(field)) {
                            where.idIn(C.listOf(array));
                        } else {
                            where.in(field, array);
                        }
                    }
                } else {
                    throw E.unexpected("Unknown  value type: %s", val.getClass());
                }
            }
        }
        ;
        abstract void applyTo(ExpressionList where, String field, Object val);
    }

    private void buildWhere(ExpressionList where, String key, Object val) {
        String[] sa = key.split("\\s+");
        switch (sa.length) {
            case 1:
                where.eq(sa[0], val);
                break;
            case 2:
                R1.valueOf(sa[1]).applyTo(where, sa[0], val);
                break;
            case 3:
                R2.valueOf(sa[2]).applyTo(where, sa[0], sa[1], val);
                break;
            default:
                throw E.unexpected("Unknown where expression: %s", key);
        }
    }

    @Override
    public EbeanQuery q(String keys, Object... values) {
        int len = values.length;
        E.illegalArgumentIf(len == 0, "no values supplied");
        String[] sa = keys.split("[,;:]+");
        E.illegalArgumentIf(sa.length != len, "The number of values does not match the number of fields");
        EbeanQuery q = q();
        ExpressionList el = q.where();
        for (int i = 0; i < len; ++i) {
            buildWhere(el, sa[i], values[i]);
        }
        return q;
    }

    @Override
    public EbeanQuery createQuery(String s, Object... objects) {
        return q(s, objects);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy