com.liferay.portal.kernel.service.persistence.impl.BasePersistenceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portal.kernel.service.persistence.impl.BasePersistenceImpl.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.portal.kernel.service.persistence.impl;

import com.liferay.expando.kernel.model.ExpandoBridge;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.configuration.Configuration;
import com.liferay.portal.kernel.configuration.Filter;
import com.liferay.portal.kernel.dao.db.DB;
import com.liferay.portal.kernel.dao.db.DBManagerUtil;
import com.liferay.portal.kernel.dao.db.DBType;
import com.liferay.portal.kernel.dao.orm.Dialect;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.EntityCache;
import com.liferay.portal.kernel.dao.orm.ORMException;
import com.liferay.portal.kernel.dao.orm.OrderFactoryUtil;
import com.liferay.portal.kernel.dao.orm.Projection;
import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
import com.liferay.portal.kernel.dao.orm.Query;
import com.liferay.portal.kernel.dao.orm.QueryPos;
import com.liferay.portal.kernel.dao.orm.Session;
import com.liferay.portal.kernel.dao.orm.SessionFactory;
import com.liferay.portal.kernel.exception.NoSuchModelException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.BaseModel;
import com.liferay.portal.kernel.model.CacheModel;
import com.liferay.portal.kernel.model.MVCCModel;
import com.liferay.portal.kernel.model.ModelListener;
import com.liferay.portal.kernel.model.ModelListenerRegistrationUtil;
import com.liferay.portal.kernel.model.ModelWrapper;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.service.ServiceContextThreadLocal;
import com.liferay.portal.kernel.service.persistence.BasePersistence;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.kernel.util.StringBundler;

import java.io.Serializable;

import java.sql.Connection;
import java.sql.Types;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

/**
 * The base implementation for all persistence classes. This class should never
 * need to be used directly.
 *
 * <p>
 * Caching information and settings can be found in
 * <code>portal.properties</code>
 * </p>
 *
 * @author Brian Wing Shun Chan
 * @author Shuyang Zhou
 * @author Peter Fellwock
 */
public class BasePersistenceImpl<T extends BaseModel<T>> implements BasePersistence<T>, SessionFactory {

    public static final String COUNT_COLUMN_NAME = "COUNT_VALUE";

    public void cacheResult(T model) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clearCache() {
    }

    @Override
    public void clearCache(List<T> model) {
    }

    @Override
    public void clearCache(T model) {
    }

    @Override
    public void closeSession(Session session) {
        _sessionFactory.closeSession(session);
    }

    @Override
    public long countWithDynamicQuery(DynamicQuery dynamicQuery) {
        return countWithDynamicQuery(dynamicQuery, ProjectionFactoryUtil.rowCount());
    }

    @Override
    public long countWithDynamicQuery(DynamicQuery dynamicQuery, Projection projection) {

        if (projection == null) {
            projection = ProjectionFactoryUtil.rowCount();
        }

        dynamicQuery.setProjection(projection);

        List<Long> results = findWithDynamicQuery(dynamicQuery);

        if (results.isEmpty()) {
            return 0;
        }

        Long firstResult = results.get(0);

        return firstResult.longValue();
    }

    @Override
    @SuppressWarnings("unchecked")
    public T fetchByPrimaryKey(Serializable primaryKey) {
        EntityCache entityCache = getEntityCache();

        Serializable serializable = entityCache.getResult(entityCacheEnabled, _modelImplClass, primaryKey);

        if (serializable == nullModel) {
            return null;
        }

        T model = (T) serializable;

        if (model == null) {
            Session session = null;

            try {
                session = openSession();

                model = (T) session.get(_modelImplClass, primaryKey);

                if (model == null) {
                    entityCache.putResult(entityCacheEnabled, _modelImplClass, primaryKey, nullModel);
                } else {
                    cacheResult(model);
                }
            } catch (Exception e) {
                entityCache.removeResult(entityCacheEnabled, _modelImplClass, primaryKey);

                throw processException(e);
            } finally {
                closeSession(session);
            }
        }

        return model;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<Serializable, T> fetchByPrimaryKeys(Set<Serializable> primaryKeys) {

        if (primaryKeys.isEmpty()) {
            return Collections.emptyMap();
        }

        if (primaryKeys.size() == 1) {
            Iterator<Serializable> iterator = primaryKeys.iterator();

            Serializable primaryKey = iterator.next();

            T model = fetchByPrimaryKey(primaryKey);

            if (model == null) {
                return Collections.emptyMap();
            }

            return Collections.singletonMap(primaryKey, model);
        }

        Map<Serializable, T> map = new HashMap<>();

        if (_modelPKType == ModelPKType.COMPOUND) {
            for (Serializable primaryKey : primaryKeys) {
                T model = fetchByPrimaryKey(primaryKey);

                if (model != null) {
                    map.put(primaryKey, model);
                }
            }

            return map;
        }

        Set<Serializable> uncachedPrimaryKeys = null;

        EntityCache entityCache = getEntityCache();

        for (Serializable primaryKey : primaryKeys) {
            Serializable serializable = entityCache.getResult(entityCacheEnabled, _modelImplClass, primaryKey);

            if (serializable != nullModel) {
                if (serializable == null) {
                    if (uncachedPrimaryKeys == null) {
                        uncachedPrimaryKeys = new HashSet<>();
                    }

                    uncachedPrimaryKeys.add(primaryKey);
                } else {
                    map.put(primaryKey, (T) serializable);
                }
            }
        }

        if (uncachedPrimaryKeys == null) {
            return map;
        }

        com.liferay.petra.string.StringBundler query = new com.liferay.petra.string.StringBundler(
                2 * uncachedPrimaryKeys.size() + 4);

        query.append(getSelectSQL());
        query.append(" WHERE ");
        query.append(getPKDBName());
        query.append(" IN (");

        if (_modelPKType == ModelPKType.STRING) {
            for (int i = 0; i < uncachedPrimaryKeys.size(); i++) {
                query.append("?");

                query.append(",");
            }
        } else {
            for (Serializable primaryKey : uncachedPrimaryKeys) {
                query.append((long) primaryKey);

                query.append(",");
            }
        }

        query.setIndex(query.index() - 1);

        query.append(")");

        String sql = query.toString();

        Session session = null;

        try {
            session = openSession();

            Query q = session.createQuery(sql);

            if (_modelPKType == ModelPKType.STRING) {
                QueryPos qPos = QueryPos.getInstance(q);

                for (Serializable primaryKey : uncachedPrimaryKeys) {
                    qPos.add(primaryKey);
                }
            }

            for (T model : (List<T>) q.list()) {
                map.put(model.getPrimaryKeyObj(), model);

                cacheResult(model);

                uncachedPrimaryKeys.remove(model.getPrimaryKeyObj());
            }

            for (Serializable primaryKey : uncachedPrimaryKeys) {
                entityCache.putResult(entityCacheEnabled, _modelImplClass, primaryKey, nullModel);
            }
        } catch (Exception e) {
            throw processException(e);
        } finally {
            closeSession(session);
        }

        return map;
    }

    @Override
    public T findByPrimaryKey(Serializable primaryKey) throws NoSuchModelException {

        throw new UnsupportedOperationException();
    }

    @Override
    public <V> List<V> findWithDynamicQuery(DynamicQuery dynamicQuery) {
        Session session = null;

        try {
            session = openSession();

            dynamicQuery.compile(session);

            return dynamicQuery.list();
        } catch (Exception e) {
            throw processException(e);
        } finally {
            closeSession(session);
        }
    }

    @Override
    public <V> List<V> findWithDynamicQuery(DynamicQuery dynamicQuery, int start, int end) {

        Session session = null;

        try {
            session = openSession();

            dynamicQuery.setLimit(start, end);

            dynamicQuery.compile(session);

            return dynamicQuery.list();
        } catch (Exception e) {
            throw processException(e);
        } finally {
            closeSession(session);
        }
    }

    @Override
    public <V> List<V> findWithDynamicQuery(DynamicQuery dynamicQuery, int start, int end,
            OrderByComparator<V> orderByComparator) {

        OrderFactoryUtil.addOrderByComparator(dynamicQuery, orderByComparator);

        return findWithDynamicQuery(dynamicQuery, start, end);
    }

    @Override
    public void flush() {
        try {
            Session session = _sessionFactory.getCurrentSession();

            if (session != null) {
                session.flush();
            }
        } catch (Exception e) {
            throw processException(e);
        }
    }

    @Override
    public Set<String> getBadColumnNames() {
        return Collections.emptySet();
    }

    public Set<String> getCompoundPKColumnNames() {
        return Collections.emptySet();
    }

    @Override
    public Session getCurrentSession() throws ORMException {
        return _sessionFactory.getCurrentSession();
    }

    @Override
    public DataSource getDataSource() {
        return _dataSource;
    }

    public DB getDB() {
        if (_db == null) {
            _db = DBManagerUtil.getDB(_dialect, _dataSource);
        }

        return _db;
    }

    @Override
    public Dialect getDialect() {
        return _dialect;
    }

    @Override
    public ModelListener<T>[] getListeners() {
        return ModelListenerRegistrationUtil.getModelListeners(getModelClass());
    }

    @Override
    public Class<T> getModelClass() {
        return _modelClass;
    }

    @Override
    public Session openNewSession(Connection connection) throws ORMException {
        return _sessionFactory.openNewSession(connection);
    }

    @Override
    public Session openSession() throws ORMException {
        return _sessionFactory.openSession();
    }

    @Override
    public SystemException processException(Exception e) {
        if (!(e instanceof ORMException)) {
            _log.error("Caught unexpected exception", e);
        } else if (_log.isDebugEnabled()) {
            _log.debug(e, e);
        }

        return new SystemException(e);
    }

    @Override
    public void registerListener(ModelListener<T> listener) {
        ModelListenerRegistrationUtil.register(listener);
    }

    @Override
    public T remove(Serializable primaryKey) throws NoSuchModelException {
        throw new UnsupportedOperationException();
    }

    @Override
    public T remove(T model) {
        while (model instanceof ModelWrapper) {
            ModelWrapper<T> modelWrapper = (ModelWrapper<T>) model;

            model = modelWrapper.getWrappedModel();
        }

        ModelListener<T>[] listeners = getListeners();

        for (ModelListener<T> listener : listeners) {
            listener.onBeforeRemove(model);
        }

        model = removeImpl(model);

        for (ModelListener<T> listener : listeners) {
            listener.onAfterRemove(model);
        }

        return model;
    }

    public void setConfiguration(Configuration configuration) {
        String modelClassName = _modelClass.getName();

        entityCacheEnabled = GetterUtil
                .getBoolean(configuration.get("value.object.entity.cache.enabled.".concat(modelClassName)), true);
        finderCacheEnabled = GetterUtil
                .getBoolean(configuration.get("value.object.finder.cache.enabled.".concat(modelClassName)), true);
    }

    @Override
    public void setDataSource(DataSource dataSource) {
        _dataSource = dataSource;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        _sessionFactory = sessionFactory;

        _dialect = _sessionFactory.getDialect();

        DBType dbType = DBManagerUtil.getDBType(_dialect);

        _databaseOrderByMaxColumns = GetterUtil
                .getInteger(PropsUtil.get(PropsKeys.DATABASE_ORDER_BY_MAX_COLUMNS, new Filter(dbType.getName())));

        databaseInMaxParameters = GetterUtil
                .getInteger(PropsUtil.get(PropsKeys.DATABASE_IN_MAX_PARAMETERS, new Filter(dbType.getName())));
    }

    @Override
    public void unregisterListener(ModelListener<T> listener) {
        ModelListenerRegistrationUtil.unregister(listener);
    }

    @Override
    public T update(T model) {
        while (model instanceof ModelWrapper) {
            ModelWrapper<T> modelWrapper = (ModelWrapper<T>) model;

            model = modelWrapper.getWrappedModel();
        }

        boolean isNew = model.isNew();

        ModelListener<T>[] listeners = getListeners();

        for (ModelListener<T> listener : listeners) {
            if (isNew) {
                listener.onBeforeCreate(model);
            } else {
                listener.onBeforeUpdate(model);
            }
        }

        model = updateImpl(model);

        for (ModelListener<T> listener : listeners) {
            if (isNew) {
                listener.onAfterCreate(model);
            } else {
                listener.onAfterUpdate(model);
            }
        }

        return model;
    }

    @Override
    public T update(T model, ServiceContext serviceContext) {
        try {
            ServiceContextThreadLocal.pushServiceContext(serviceContext);

            return update(model);
        } finally {
            ServiceContextThreadLocal.popServiceContext();
        }
    }

    protected static String removeConjunction(String sql) {
        int pos = sql.indexOf(" AND ");

        if (pos != -1) {
            sql = sql.substring(0, pos);
        }

        return sql;
    }

    protected void appendOrderByComparator(com.liferay.petra.string.StringBundler sb, String entityAlias,
            OrderByComparator<T> orderByComparator) {

        appendOrderByComparator(sb, entityAlias, orderByComparator, false);
    }

    protected void appendOrderByComparator(com.liferay.petra.string.StringBundler sb, String entityAlias,
            OrderByComparator<T> orderByComparator, boolean sqlQuery) {

        sb.append(ORDER_BY_CLAUSE);

        String[] orderByFields = orderByComparator.getOrderByFields();

        int length = orderByFields.length;

        if ((_databaseOrderByMaxColumns > 0) && (_databaseOrderByMaxColumns < length)) {

            length = _databaseOrderByMaxColumns;
        }

        for (int i = 0; i < length; i++) {
            sb.append(getColumnName(entityAlias, orderByFields[i], sqlQuery));

            if ((i + 1) < length) {
                if (orderByComparator.isAscending(orderByFields[i])) {
                    sb.append(ORDER_BY_ASC_HAS_NEXT);
                } else {
                    sb.append(ORDER_BY_DESC_HAS_NEXT);
                }
            } else {
                if (orderByComparator.isAscending(orderByFields[i])) {
                    sb.append(ORDER_BY_ASC);
                } else {
                    sb.append(ORDER_BY_DESC);
                }
            }
        }
    }

    /**
     * @deprecated As of Judson (7.1.x), replaced by {@link
     *             #appendOrderByComparator(
     *             com.liferay.petra.string.Stringbundler, String,
     *             OrderByComparator)}
     */
    @Deprecated
    protected void appendOrderByComparator(StringBundler sb, String entityAlias,
            OrderByComparator<T> orderByComparator) {

        appendOrderByComparator(sb, entityAlias, orderByComparator, false);
    }

    /**
     * @deprecated As of Judson (7.1.x), replaced by {@link
     *             #appendOrderByComparator(
     *             com.liferay.petra.string.Stringbundler, String,
     *             OrderByComparator, boolean)}
     */
    @Deprecated
    protected void appendOrderByComparator(StringBundler sb, String entityAlias,
            OrderByComparator<T> orderByComparator, boolean sqlQuery) {

        com.liferay.petra.string.StringBundler petraSB = new com.liferay.petra.string.StringBundler(
                sb.getStrings());

        int index = sb.index();

        petraSB.setIndex(index);

        appendOrderByComparator(petraSB, entityAlias, orderByComparator, sqlQuery);

        for (int i = index; i < petraSB.index(); i++) {
            sb.append(petraSB.stringAt(i));
        }
    }

    protected ClassLoader getClassLoader() {
        Class<?> clazz = getClass();

        return clazz.getClassLoader();
    }

    protected String getColumnName(String entityAlias, String fieldName, boolean sqlQuery) {

        String columnName = _dbColumnNames.getOrDefault(fieldName, fieldName);

        if (sqlQuery) {
            fieldName = columnName;
        } else {
            Set<String> compoundPKColumnNames = getCompoundPKColumnNames();

            if (compoundPKColumnNames.contains(fieldName)) {
                fieldName = "id.".concat(fieldName);
            }
        }

        fieldName = entityAlias.concat(fieldName);

        Map<String, Integer> tableColumnsMap = getTableColumnsMap();

        Integer type = tableColumnsMap.get(columnName);

        if (type == null) {
            throw new IllegalArgumentException("Unknown column name " + columnName);
        }

        if (type == Types.CLOB) {
            fieldName = CAST_CLOB_TEXT_OPEN.concat(fieldName).concat(StringPool.CLOSE_PARENTHESIS);
        }

        return fieldName;
    }

    protected EntityCache getEntityCache() {
        throw new UnsupportedOperationException();
    }

    protected String getPKDBName() {
        throw new UnsupportedOperationException();
    }

    protected String getSelectSQL() {
        throw new UnsupportedOperationException();
    }

    protected Map<String, Integer> getTableColumnsMap() {
        throw new UnsupportedOperationException();
    }

    /**
     * Removes the model instance from the database. {@link #update(BaseModel,
     * boolean)} depends on this method to implement the remove operation; it
     * only notifies the model listeners.
     *
     * @param  model the model instance to remove
     * @return the model instance that was removed
     */
    protected T removeImpl(T model) {
        throw new UnsupportedOperationException();
    }

    protected void setDBColumnNames(Map<String, String> dbColumnNames) {
        _dbColumnNames = dbColumnNames;
    }

    protected void setEntityCacheEnabled(boolean entityCacheEnabled) {
        this.entityCacheEnabled = entityCacheEnabled;
    }

    protected void setModelClass(Class<T> modelClass) {
        _modelClass = modelClass;
    }

    protected void setModelImplClass(Class<? extends T> modelImplClass) {
        _modelImplClass = modelImplClass;
    }

    protected void setModelPKClass(Class<? extends Serializable> clazz) {
        if (clazz.isPrimitive()) {
            _modelPKType = ModelPKType.NUMBER;
        } else if (String.class.isAssignableFrom(clazz)) {
            _modelPKType = ModelPKType.STRING;
        }
    }

    /**
     * Updates the model instance in the database or adds it if it does not yet
     * exist. {@link #remove(BaseModel)} depends on this method to implement the
     * update operation; it only notifies the model listeners.
     *
     * @param  model the model instance to update
     * @return the model instance that was updated
     */
    protected T updateImpl(T model) {
        throw new UnsupportedOperationException();
    }

    protected static final String CAST_CLOB_TEXT_OPEN = "CAST_CLOB_TEXT(";

    protected static final Object[] FINDER_ARGS_EMPTY = new Object[0];

    /**
     * @deprecated As of Mueller (7.2.x), with no direct replacement
     */
    @Deprecated
    protected static final Comparator<String> NULL_SAFE_STRING_COMPARATOR = Comparator
            .nullsLast(Comparator.naturalOrder());

    protected static final String ORDER_BY_ASC = " ASC";

    protected static final String ORDER_BY_ASC_HAS_NEXT = " ASC, ";

    protected static final String ORDER_BY_CLAUSE = " ORDER BY ";

    protected static final String ORDER_BY_DESC = " DESC";

    protected static final String ORDER_BY_DESC_HAS_NEXT = " DESC, ";

    protected static final String WHERE_AND = " AND ";

    protected static final String WHERE_GREATER_THAN = " >= ? ";

    protected static final String WHERE_GREATER_THAN_HAS_NEXT = " >= ? AND ";

    protected static final String WHERE_LESSER_THAN = " <= ? ";

    protected static final String WHERE_LESSER_THAN_HAS_NEXT = " <= ? AND ";

    protected static final String WHERE_OR = " OR ";

    protected static final NullModel nullModel = new NullModel();

    protected int databaseInMaxParameters;
    protected Map<String, String> dbColumnNames;
    protected boolean entityCacheEnabled;
    protected boolean finderCacheEnabled;

    private static final Log _log = LogFactoryUtil.getLog(BasePersistenceImpl.class);

    private int _databaseOrderByMaxColumns;
    private DataSource _dataSource;
    private DB _db;
    private Map<String, String> _dbColumnNames = Collections.emptyMap();
    private Dialect _dialect;
    private Class<T> _modelClass;
    private Class<? extends T> _modelImplClass;
    private ModelPKType _modelPKType = ModelPKType.COMPOUND;
    private SessionFactory _sessionFactory;

    private static class NullModel implements BaseModel<NullModel>, CacheModel<NullModel>, MVCCModel {

        @Override
        public Object clone() {
            return this;
        }

        @Override
        public int compareTo(NullModel nullModel) {
            throw new UnsupportedOperationException();
        }

        @Override
        public ExpandoBridge getExpandoBridge() {
            throw new UnsupportedOperationException();
        }

        @Override
        public Map<String, Object> getModelAttributes() {
            throw new UnsupportedOperationException();
        }

        @Override
        public Class<?> getModelClass() {
            throw new UnsupportedOperationException();
        }

        @Override
        public String getModelClassName() {
            throw new UnsupportedOperationException();
        }

        @Override
        public long getMvccVersion() {
            return -1;
        }

        @Override
        public Serializable getPrimaryKeyObj() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isCachedModel() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isEntityCacheEnabled() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isEscapedModel() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isFinderCacheEnabled() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isNew() {
            throw new UnsupportedOperationException();
        }

        @Override
        public void resetOriginalValues() {
        }

        @Override
        public void setCachedModel(boolean cachedModel) {
        }

        @Override
        public void setExpandoBridgeAttributes(BaseModel<?> baseModel) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setExpandoBridgeAttributes(ExpandoBridge expandoBridge) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setExpandoBridgeAttributes(ServiceContext serviceContext) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setModelAttributes(Map<String, Object> attributes) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setMvccVersion(long mvccVersion) {
        }

        @Override
        public void setNew(boolean n) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void setPrimaryKeyObj(Serializable primaryKeyObj) {
            throw new UnsupportedOperationException();
        }

        @Override
        public CacheModel<NullModel> toCacheModel() {
            return nullModel;
        }

        @Override
        public NullModel toEntityModel() {
            return nullModel;
        }

        @Override
        public NullModel toEscapedModel() {
            throw new UnsupportedOperationException();
        }

        @Override
        public NullModel toUnescapedModel() {
            throw new UnsupportedOperationException();
        }

        @Override
        public String toXmlString() {
            throw new UnsupportedOperationException();
        }

    }

    private enum ModelPKType {

        COMPOUND, NUMBER, STRING

    }

}