/**
* 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.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.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.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.NullSafeStringComparator;
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 com.liferay.portal.kernel.util.StringPool;
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.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";
@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;
}
else {
return (results.get(0)).longValue();
}
}
@Override
public T fetchByPrimaryKey(Serializable primaryKey) {
throw new UnsupportedOperationException();
}
@Override
public Map<Serializable, T> fetchByPrimaryKeys(
Set<Serializable> primaryKeys) {
throw new UnsupportedOperationException();
}
@Override
@SuppressWarnings("unused")
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();
}
@Override
public Session getCurrentSession() throws ORMException {
return _sessionFactory.getCurrentSession();
}
@Override
public DataSource getDataSource() {
return _dataSource;
}
public DB getDB() {
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
@SuppressWarnings("unused")
public T remove(Serializable primaryKey) throws NoSuchModelException {
throw new UnsupportedOperationException();
}
@Override
public T remove(T model) {
if (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;
}
@Override
public void setDataSource(DataSource dataSource) {
_dataSource = dataSource;
}
public void setSessionFactory(SessionFactory sessionFactory) {
_sessionFactory = sessionFactory;
_dialect = _sessionFactory.getDialect();
_db = DBManagerUtil.getDB(_dialect, getDataSource());
DBType dbType = _db.getDBType();
_databaseOrderByMaxColumns = GetterUtil.getInteger(
PropsUtil.get(
PropsKeys.DATABASE_ORDER_BY_MAX_COLUMNS,
new Filter(dbType.getName())));
}
@Override
public void unregisterListener(ModelListener<T> listener) {
ModelListenerRegistrationUtil.unregister(listener);
}
@Override
public T update(T model) {
if (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);
update(model);
return 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(
StringBundler query, String entityAlias,
OrderByComparator<T> orderByComparator) {
appendOrderByComparator(query, entityAlias, orderByComparator, false);
}
protected void appendOrderByComparator(
StringBundler query, String entityAlias,
OrderByComparator<T> orderByComparator, boolean sqlQuery) {
query.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++) {
query.append(
getColumnName(entityAlias, orderByFields[i], sqlQuery));
if ((i + 1) < length) {
if (orderByComparator.isAscending(orderByFields[i])) {
query.append(ORDER_BY_ASC_HAS_NEXT);
}
else {
query.append(ORDER_BY_DESC_HAS_NEXT);
}
}
else {
if (orderByComparator.isAscending(orderByFields[i])) {
query.append(ORDER_BY_ASC);
}
else {
query.append(ORDER_BY_DESC);
}
}
}
}
protected ClassLoader getClassLoader() {
Class<?> clazz = getClass();
return clazz.getClassLoader();
}
protected String getColumnName(
String entityAlias, String fieldName, boolean sqlQuery) {
String columnName = _getDBColumnName(fieldName);
if (sqlQuery) {
fieldName = columnName;
}
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 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 setModelClass(Class<T> modelClass) {
_modelClass = modelClass;
}
/**
* 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];
protected static final Comparator<String> NULL_SAFE_STRING_COMPARATOR =
new NullSafeStringComparator();
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();
/**
* @deprecated As of 7.0.0, with no direct replacement
*/
@Deprecated
protected ModelListener<T>[] listeners = new ModelListener[0];
private String _getDBColumnName(String fieldName) {
if (_dbColumnNames == null) {
Map<String, String> dbColumnNames = new HashMap<>();
for (String badColumnName : getBadColumnNames()) {
dbColumnNames.put(
badColumnName, badColumnName.concat(StringPool.UNDERLINE));
}
_dbColumnNames = dbColumnNames;
}
return _dbColumnNames.getOrDefault(fieldName, fieldName);
}
private static final Log _log = LogFactoryUtil.getLog(
BasePersistenceImpl.class);
private int _databaseOrderByMaxColumns;
private DataSource _dataSource;
private DB _db;
private Map<String, String> _dbColumnNames;
private Dialect _dialect;
private Class<T> _modelClass;
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 this;
}
@Override
public NullModel toEntityModel() {
return this;
}
@Override
public NullModel toEscapedModel() {
throw new UnsupportedOperationException();
}
@Override
public NullModel toUnescapedModel() {
throw new UnsupportedOperationException();
}
@Override
public String toXmlString() {
throw new UnsupportedOperationException();
}
}
}