com.diversityarrays.dal.db.bms.BMS_DalDatabase.java Source code

Java tutorial

Introduction

Here is the source code for com.diversityarrays.dal.db.bms.BMS_DalDatabase.java

Source

/*
 * dalserver-interop library - implementation of DAL server for interoperability
 * Copyright (C) 2015  Diversity Arrays Technology
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.diversityarrays.dal.db.bms;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.pearcan.util.StringUtil;

import org.apache.commons.collections15.Closure;
import org.apache.commons.collections15.ClosureUtils;

import com.diversityarrays.dal.db.AbstractDalDatabase;
import com.diversityarrays.dal.db.AuthenticationException;
import com.diversityarrays.dal.db.CollectionEntityIterator;
import com.diversityarrays.dal.db.DalDatabaseUtil;
import com.diversityarrays.dal.db.DalDbException;
import com.diversityarrays.dal.db.DalResponseBuilder;
import com.diversityarrays.dal.db.DbUtil;
import com.diversityarrays.dal.db.EntityIterator;
import com.diversityarrays.dal.db.EntityProvider;
import com.diversityarrays.dal.db.RecordCountCache;
import com.diversityarrays.dal.db.RecordCountCacheEntry;
import com.diversityarrays.dal.db.RecordCountCacheImpl;
import com.diversityarrays.dal.db.ResultSetEntityIterator;
import com.diversityarrays.dal.db.SystemGroupInfo;
import com.diversityarrays.dal.db.UserInfo;
import com.diversityarrays.dal.entity.DalEntity;
import com.diversityarrays.dal.entity.Genotype;
import com.diversityarrays.dal.entity.GenotypeAlias;
import com.diversityarrays.dal.entity.Genus;
import com.diversityarrays.dal.ops.DalOperation;
import com.diversityarrays.dal.server.DalSession;
import com.diversityarrays.dal.service.DalDbNotYetImplementedException;
import com.diversityarrays.dal.sqldb.JdbcConnectionParameters;
import com.diversityarrays.dal.sqldb.ResultSetVisitor;
import com.diversityarrays.dal.sqldb.SqlUtil;
import com.diversityarrays.dalclient.SessionExpiryOption;
import com.diversityarrays.util.Continue;
import com.diversityarrays.util.Either;

/**
 * Provides an implementation of DalDatabase that understands the
 * old BMS database schema (GMS).
 * @author brian
 *
 */
public class BMS_DalDatabase extends AbstractDalDatabase {

    private static final String DATABASE_VERSION = "0.1";

    static class BMS_SystemGroupInfo implements SystemGroupInfo {

        private final String groupId;
        private final String groupName;
        private final boolean groupOwner;

        BMS_SystemGroupInfo(String groupId, String groupName, boolean groupOwner) {
            this.groupId = groupId;
            this.groupName = groupName;
            this.groupOwner = groupOwner;
        }

        @Override
        public String getGroupId() {
            return groupId;
        }

        @Override
        public String getGroupName() {
            return groupName;
        }

        @Override
        public boolean isGroupOwner() {
            return groupOwner;
        }

    }

    static class BMS_UserInfo implements UserInfo {

        private String userName;
        private String userId;

        public final int instalid;
        public final int ustatus;
        public final int utype;
        public final int personid;
        public final String adate;

        BMS_UserInfo(String nm, int id, int instalid, int ustatus, int uaccess, int utype, int pid, String adate) {
            this.userName = nm;
            this.userId = Integer.toString(id);

            this.instalid = instalid;
            this.ustatus = ustatus;
            this.utype = utype;
            this.personid = pid;
            this.adate = adate;
        }

        @Override
        public String getUserName() {
            return userName;
        }

        @Override
        public String getUserId() {
            return userId;
        }

    }

    // GenotypeAliasType:
    // SELECT fcode, fname, fldno, COUNT(*) FROM UDFLDS
    // WHERE ftable='NAMES' AND ftype='NAME'

    // Need to choose one as the primary name
    // Use ordered from the parameter

    public static final Closure<String> REPORT_PROGRESS = new Closure<String>() {
        String prefix = BMS_DalDatabase.class.getSimpleName() + ": ";

        @Override
        public void execute(String msg) {
            System.out.println(prefix + msg);
        }
    };

    static DalDbException getDalDbException(Either<Throwable, ?> either) {
        if (either.isRight()) {
            return new DalDbException("Internal error: getDalDbException() called with no error");
        }
        Throwable t = either.left();
        if (t instanceof DalDbException) {
            return (DalDbException) t;
        }
        return new DalDbException(t);
    }

    private final JdbcConnectionParameters localParams;
    private final JdbcConnectionParameters centralParams;

    private BmsConnectionInfo bmsConnections;

    private List<DalOperation> operations;

    private Map<String, BMS_UserInfo> userInfoBySessionId = new HashMap<String, BMS_UserInfo>();

    private Map<String, Class<? extends DalEntity>> entityClassByName = new HashMap<String, Class<? extends DalEntity>>();

    private EntityProvider<Genus> genusProvider = new EntityProvider<Genus>() {

        @Override
        public Genus getEntity(String id, String filterClause) throws DalDbNotYetImplementedException {
            if (filterClause != null) {
                throw new DalDbNotYetImplementedException("Filtering clause for genus");
            }
            // TODO use the genus table
            return bmsConnections.genusStore.getGenusById(id);
        }

        @Override
        public EntityIterator<? extends Genus> createIterator(int firstRecord, int nRecords, String filterClause)
                throws DalDbNotYetImplementedException {
            if (filterClause != null) {
                throw new DalDbNotYetImplementedException("Filtering clause for genus");
            }
            // TODO use the genus table
            return new CollectionEntityIterator<Genus>(bmsConnections.genusStore.getGenusValues());
        }

        @Override
        public int getEntityCount(String filterClause) throws DalDbNotYetImplementedException {
            if (filterClause != null) {
                throw new DalDbNotYetImplementedException("Filtering clause for genus");
            }
            // TODO use the genus table
            return bmsConnections.genusStore.getGenusCount();
        }

        @Override
        public EntityIterator<? extends Genus> createIdIterator(String id, int firstRecord, int nRecords,
                String filterClause) throws DalDbException {
            throw new UnsupportedOperationException();
        }
    };

    private EntityProvider<Genotype> genotypeProvider = new EntityProvider<Genotype>() {

        private GenotypeFactory createFactory() {
            return new GenotypeFactory(bmsConnections.genusStore);
        }

        @Override
        public int getEntityCount(String filterClause) throws DalDbException {
            String sql = createFactory().createCountQuery(filterClause);
            int total = 0;
            for (Connection c : bmsConnections.getConnections()) {
                total += SqlUtil.getSingleInteger(c, sql);
            }
            return total;
        }

        @Override
        public Genotype getEntity(String id, String filterClause) throws DalDbException {

            final GenotypeFactory factory = createFactory();

            try {
                final Genotype[] result = new Genotype[1];

                ResultSetVisitor visitor = new ResultSetVisitor() {
                    @Override
                    public Continue visit(ResultSet rs) {
                        try {
                            result[0] = factory.createEntity(rs);
                        } catch (DalDbException e) {
                            return Continue.error(e);
                        }
                        return Continue.STOP; // only the first
                    }
                };

                String sql = factory.createGetQuery(id, filterClause);

                Connection c = bmsConnections.getConnectionFor(id);
                if (c != null) {
                    Continue cont = SqlUtil.performQuery(c, sql, visitor);
                    if (cont.isError()) {
                        Throwable t = cont.throwable;
                        if (t instanceof DalDbException) {
                            throw ((DalDbException) t);
                        }
                        throw new DalDbException(t);
                    }
                }

                return result[0];
            } finally {
                try {
                    factory.close();
                } catch (IOException ignore) {
                }
            }
        }

        @Override
        public EntityIterator<? extends Genotype> createIterator(int firstRecord, int nRecords, String filterClause)
                throws DalDbException {

            String whereClause = GenotypeFactory.buildWhereAndLimit(filterClause, nRecords, firstRecord);

            StringBuilder sb = GenotypeFactory.createBaseQuery("g", "a", bmsConnections.getFldnoForGenus(),
                    whereClause);

            String sql = sb.toString();

            GenotypeFactory factory = createFactory();

            try {
                Statement stmt = SqlUtil.createQueryStatement(bmsConnections.centralConnection);
                ResultSet rs = stmt.executeQuery(sql);

                return new ResultSetEntityIterator<Genotype>(stmt, rs, factory);
            } catch (SQLException e) {
                throw new DalDbException(e);
            } finally {
                try {
                    factory.close();
                } catch (IOException ignore) {
                }
            }
        }

        @Override
        public EntityIterator<? extends Genotype> createIdIterator(String id, int firstRecord, int nRecords,
                String filterClause) throws DalDbException {
            throw new UnsupportedOperationException();
        }

    };

    private EntityProvider<GenotypeAlias> genotypeAliasProvider = new EntityProvider<GenotypeAlias>() {

        GenotypeAliasFactory genotypeAliasFactory = new GenotypeAliasFactory();

        @Override
        public int getEntityCount(String filterClause) throws DalDbException {
            String sql = genotypeAliasFactory.createCountQuery(filterClause);
            // TODO count across both connections
            return SqlUtil.getSingleInteger(bmsConnections.centralConnection, sql);
        }

        @Override
        public GenotypeAlias getEntity(String id, String filterClause) throws DalDbException {

            final GenotypeAlias[] result = new GenotypeAlias[1];

            ResultSetVisitor visitor = new ResultSetVisitor() {
                @Override
                public Continue visit(ResultSet rs) {
                    try {
                        result[0] = genotypeAliasFactory.createEntity(rs);
                    } catch (DalDbException e) {
                        return Continue.error(e);
                    }
                    return Continue.STOP; // only the first
                }
            };

            String sql = genotypeAliasFactory.createGetQuery(id, filterClause);

            // TODO query across both? but what about the JOIN?
            Continue cont = SqlUtil.performQuery(bmsConnections.centralConnection, sql, visitor);

            if (cont.isError()) {
                Throwable t = cont.throwable;
                if (t instanceof DalDbException) {
                    throw ((DalDbException) t);
                }
                throw new DalDbException(t);
            }

            return result[0];
        }

        @Override
        public EntityIterator<? extends GenotypeAlias> createIterator(int firstRecord, int nRecords,
                String filterClause) throws DalDbException {

            String sql = genotypeAliasFactory.createPagedListQuery(firstRecord, nRecords, filterClause);

            try {
                // TODO query across both? but what about the JOIN?
                Statement stmt = SqlUtil.createQueryStatement(bmsConnections.centralConnection);
                ResultSet rs = stmt.executeQuery(sql);

                return new ResultSetEntityIterator<GenotypeAlias>(stmt, rs, genotypeAliasFactory);
            } catch (SQLException e) {
                throw new DalDbException(e);
            }
        }

        @Override
        public EntityIterator<? extends GenotypeAlias> createIdIterator(String id, int firstRecord, int nRecords,
                String filterClause) throws DalDbException {

            String sql = genotypeAliasFactory.createListAliasQuery(id, firstRecord, nRecords, filterClause);

            try {
                // TODO query across both? but what about the JOIN?
                Statement stmt = SqlUtil.createQueryStatement(bmsConnections.centralConnection);
                ResultSet rs = stmt.executeQuery(sql);

                return new ResultSetEntityIterator<GenotypeAlias>(stmt, rs, genotypeAliasFactory);
            } catch (SQLException e) {
                throw new DalDbException(e);
            }
        }
    };

    public BMS_DalDatabase(Closure<String> progress, boolean initialise, JdbcConnectionParameters localParams,
            JdbcConnectionParameters centralParams) throws DalDbException {
        super("BMS-Interop[Central=" + centralParams + " Local=" + localParams + "]");

        this.localParams = localParams;
        this.centralParams = centralParams;

        if (localParams != null) {
            String local = StringUtil.substringBefore(localParams.connectionUrl, "?");
            String central = StringUtil.substringBefore(centralParams.connectionUrl, "?");
            if (local.equals(central)) {
                throw new DalDbException(
                        "Local and Central connectionUrls may NOT point at the same database:: " + local);
            }
        }

        entityClassByName.put("genus", Genus.class);
        entityClassByName.put("genotype", Genotype.class);

        if (initialise) {
            getBmsConnections(progress, true);
        }
    }

    @Override
    public boolean isInitialiseRequired() {
        return true;
    }

    @Override
    public void initialise(Closure<String> progress) throws DalDbException {
        getBmsConnections(progress, true);
    }

    private BmsConnectionInfo getBmsConnections(Closure<String> progress, boolean createIfNotPresent)
            throws DalDbException {
        if (bmsConnections == null && createIfNotPresent) {
            bmsConnections = new BmsConnectionInfo(localParams, centralParams, progress);
        }
        return bmsConnections;
    }

    @Override
    public String getDatabaseVersion(DalSession session) {
        return DATABASE_VERSION;
    }

    @Override
    public List<DalOperation> getOperations() {
        if (operations == null) {
            synchronized (this) {
                if (operations == null) {
                    List<DalOperation> tmp = new ArrayList<DalOperation>();

                    tmp.add(createOperation("get/genus/_id", Genus.class, genusProvider));
                    tmp.add(createOperation("list/genus", Genus.class, genusProvider));

                    tmp.add(createOperation("get/genotype/_id", Genotype.class, genotypeProvider));
                    tmp.add(createOperation("list/genotype/_nperpage/page/_num", Genotype.class, genotypeProvider));

                    tmp.add(createOperation("get/genotypealias/_id", GenotypeAlias.class, genotypeAliasProvider));
                    tmp.add(createOperation("list/genotypealias/_nperpage/page/_num", GenotypeAlias.class,
                            genotypeAliasProvider));

                    //               tmp.add(createOperation("genus/_genusid/list/genotype", Genotype.class, genusGenotypeProvider));
                    //               tmp.add(createOperation("genus/_genusid/list/genotype/_nperpage/page/_num", Genotype.class, genusGenotypeProvider));

                    tmp.add(createOperation("genotype/_genoid/list/alias", GenotypeAlias.class,
                            genotypeAliasProvider));

                    operations = tmp;
                }
            }
        }
        return operations;
    }

    private Map<Pattern, MatcherToOperation> factoryByPattern;

    private Collection<String> entityNames;

    @SuppressWarnings("unchecked")
    private Closure<String> defaultProgress = ClosureUtils.nopClosure();

    static interface MatcherToOperation {
        public DalOperation makeOperation(Matcher m, Class<? extends DalEntity> entityClass,
                EntityProvider<? extends DalEntity> provider);
    }

    protected DalOperation createOperation(String template, Class<? extends DalEntity> entityClass,
            EntityProvider<? extends DalEntity> provider) {
        if (factoryByPattern == null) {
            factoryByPattern = createFactoryByPattern();
        }

        DalOperation result = null;

        for (Pattern p : factoryByPattern.keySet()) {
            Matcher m = p.matcher(template);
            if (m.matches()) {
                result = factoryByPattern.get(p).makeOperation(m, entityClass, provider);
                break;
            }
        }

        if (result == null) {
            throw new IllegalArgumentException("Unsupported operation template: '" + template + "'");
        }

        return result;
    }

    @SuppressWarnings("unchecked")
    public void setDefaultProgress(Closure<String> p) {
        this.defaultProgress = p != null ? p : ClosureUtils.nopClosure();
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected Map<Pattern, MatcherToOperation> createFactoryByPattern() {

        Map<Pattern, MatcherToOperation> map = new HashMap<Pattern, MatcherToOperation>();

        map.put(GetOperation.PATTERN, new MatcherToOperation() {
            @Override
            public DalOperation makeOperation(Matcher m, Class<? extends DalEntity> entityClass,
                    EntityProvider<? extends DalEntity> provider) {
                String entity = GetOperation.getEntityName(m);
                return new GetOperation(BMS_DalDatabase.this, entity, "get/" + entity + "/_id", entityClass,
                        provider);
            }
        });

        map.put(SimpleListOperation.PATTERN, new MatcherToOperation() {
            @Override
            public DalOperation makeOperation(Matcher m, Class<? extends DalEntity> entityClass,
                    EntityProvider<? extends DalEntity> provider) {
                String entity = SimpleListOperation.getEntityName(m);
                return new SimpleListOperation(BMS_DalDatabase.this, entity, entityClass, provider);
            }
        });

        map.put(PagedListOperation.PATTERN, new MatcherToOperation() {
            @Override
            public DalOperation makeOperation(Matcher m, Class<? extends DalEntity> entityClass,
                    EntityProvider<? extends DalEntity> provider) {
                String entity = PagedListOperation.getEntityName(m);
                return new PagedListOperation(BMS_DalDatabase.this, entity, entityClass, provider);
            }
        });

        map.put(GenotypeListAliasOperation.PATTERN, new MatcherToOperation() {
            @Override
            public DalOperation makeOperation(Matcher m, Class<? extends DalEntity> entityClass,
                    EntityProvider<? extends DalEntity> provider) {
                return new GenotypeListAliasOperation(BMS_DalDatabase.this,
                        (EntityProvider<GenotypeAlias>) provider);
            }
        });

        //      map.put(GenotypeListSpecimenOperation.PATTERN, new MatcherToOperation() {
        //         @Override
        //         public DalOperation makeOperation(Matcher m, Class<? extends DalEntity> entityClass, EntityProvider<? extends DalEntity> provider) {
        //            return new GenotypeListSpecimenOperation(BMS_DalDatabase.this, (EntityProvider<Specimen>) provider);
        //         }
        //      });

        return map;
    }

    @Override
    public Collection<String> getEntityNames() {
        if (entityNames == null) {
            Set<String> set = new HashSet<String>();
            for (DalOperation op : getOperations()) {
                set.add(op.getEntityName());
            }
            entityNames = set;
        }
        return entityNames;
    }

    @Override
    public SystemGroupInfo getSystemGroupInfo(DalSession session) throws DalDbException {

        BMS_UserInfo userInfo = userInfoBySessionId.get(session.sessionId);

        if (userInfo == null) {
            throw new DalDbException("Not logged in");
        }

        UdfldsRecord udfldsRecord = bmsConnections.userTypesByFldno.get(userInfo.utype);
        if (udfldsRecord == null) {
            throw new DalDbException("Missing UDFLDS record for utype=" + userInfo.utype);
        }

        boolean owner = udfldsRecord.fname.contains("ADMINISTRATOR");

        BMS_SystemGroupInfo result = new BMS_SystemGroupInfo(session.getGroupId(), udfldsRecord.fname, owner);

        return result;
    }

    @Override
    public void performListAllGroup(DalSession session, DalResponseBuilder builder, String[] returnSql)
            throws DalDbException {
        BMS_UserInfo userInfo = userInfoBySessionId.get(session.sessionId);
        if (userInfo == null) {
            throw new DalDbException("Not logged in");
        }

        builder.addResponseMeta("SystemGroup");

        for (UdfldsRecord r : bmsConnections.userTypesByFldno.values()) {
            builder.startTag("SystemGroup").attribute("SystemGroupId", Integer.toString(r.fldno))
                    .attribute("SystemGroupName", r.fcode).attribute("SystemGroupDescription", r.fname).endTag();
        }
    }

    @Override
    public void performListGroup(DalSession session, DalResponseBuilder builder, String[] returnSql)
            throws DalDbException {
        BMS_UserInfo userInfo = userInfoBySessionId.get(session.sessionId);
        if (userInfo == null) {
            throw new DalDbException("Not logged in");
        }

        builder.addResponseMeta("SystemGroup");

        UdfldsRecord r = bmsConnections.userTypesByFldno.get(userInfo.utype);
        if (r == null) {
            System.err.println("WARNING: Missing UDFLDS record for utype=" + userInfo.utype);

            builder.startTag("SystemGroup").attribute("SystemGroupId", "0")
                    .attribute("SystemGroupName", "Unknown-" + userInfo.utype)
                    .attribute("SystemGroupDescription", "Missing UDFLDS record for utype=" + userInfo.utype)
                    .endTag();
        } else {
            builder.startTag("SystemGroup").attribute("SystemGroupId", Integer.toString(r.fldno))
                    .attribute("SystemGroupName", r.fcode).attribute("SystemGroupDescription", r.fname).endTag();
        }
    }

    @Override
    public UserInfo doLogin(String newSessionId, final String userName, SessionExpiryOption seo,
            final Map<String, String> parms) throws AuthenticationException {
        String sql = "SELECT userid, upswd, instalid, ustatus, uaccess, utype, personid, adate FROM users WHERE uname = '"
                + DbUtil.doubleUpSingleQuote(userName.toUpperCase()) + "'";

        final BMS_UserInfo[] result = new BMS_UserInfo[1];
        ResultSetVisitor visitor = new ResultSetVisitor() {
            @Override
            public Continue visit(ResultSet rs) {
                try {
                    int userid = rs.getInt(1);
                    String pswd = rs.getString(2);

                    int instalid = rs.getInt(3);
                    int ustatus = rs.getInt(4);
                    int uaccess = rs.getInt(5);
                    int utype = rs.getInt(6);
                    int pid = rs.getInt(7);
                    String adate = rs.getString(8);

                    String errmsg = DalDatabaseUtil.getUsernamePasswordErrorMessage(userName, pswd, parms);

                    if (errmsg != null) {
                        return Continue.error(new AuthenticationException(errmsg));
                    }

                    result[0] = new BMS_UserInfo(userName, userid, instalid, ustatus, uaccess, utype, pid, adate);

                    return Continue.STOP; // Only want the first match?
                } catch (SQLException e) {
                    return Continue.error(e);
                }
            }
        };

        Continue qResult = null;

        try {
            qResult = SqlUtil.performQuery(getBmsConnections(defaultProgress, true).centralConnection, sql,
                    visitor);
        } catch (DalDbException e) {
            throw new AuthenticationException(e);
        }

        if (qResult.isError()) {
            Throwable t = qResult.throwable;
            if (t instanceof AuthenticationException) {
                throw (AuthenticationException) t;
            }
            throw new AuthenticationException("Internal error", qResult.throwable);
        }

        BMS_UserInfo ui = result[0];

        if (ui == null) {
            throw new AuthenticationException("Invalid username or password");
        }

        userInfoBySessionId.put(newSessionId, ui);

        return ui;
    }

    @Override
    public String getDatabasePath() {
        StringBuilder sb = new StringBuilder();
        sb.append(centralParams).append("$$").append(localParams);
        return sb.toString();
    }

    @Override
    public void shutdown() throws DalDbException {
        if (bmsConnections != null) {
            try {
                bmsConnections.closeConnections();
            } finally {
                bmsConnections = null;
            }
        }
    }

    @Override
    public Class<? extends DalEntity> getEntityClass(String tname) {
        Class<? extends DalEntity> result = null;
        for (String name : entityClassByName.keySet()) {
            if (name.equalsIgnoreCase(tname)) {
                result = entityClassByName.get(name);
                break;
            }
        }
        return result;
    }

    @Override
    public void performListField(DalSession session, String tableName, DalResponseBuilder responseBuilder)
            throws DalDbException {

        Class<? extends DalEntity> entityClass = getEntityClass(tableName);
        if (entityClass == null) {
            throw new DalDbException("Unknown tableName: '" + tableName + "'");
        }

        DalDatabaseUtil.addEntityFields(entityClass, responseBuilder);
    }

    @Override
    public void doLogout(DalSession session) {
        recordCountCache.removeEntriesFor(session);
        BMS_UserInfo ui = userInfoBySessionId.remove(session.sessionId);
        if (ui != null) {
            // Do something else maybe ?
        }
    }

    private final RecordCountCache recordCountCache = new RecordCountCacheImpl();

    public RecordCountCacheEntry getRecordCountCacheEntry(DalSession session, Class<?> entityClass) {
        return recordCountCache.getEntry(session, entityClass);
    }

    public void setRecordCountCacheEntry(DalSession session, Class<?> entityClass, String filterClause, int count) {
        recordCountCache.setEntry(session, entityClass, filterClause, count);
    }
}