/** * 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.sync.engine.service.persistence; import com.j256.ormlite.dao.BaseDaoImpl; import com.j256.ormlite.field.DataPersister; import com.j256.ormlite.field.FieldType; import com.j256.ormlite.jdbc.JdbcPooledConnectionSource; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; import com.liferay.sync.engine.model.BaseModel; import com.liferay.sync.engine.model.ModelListener; import com.liferay.sync.engine.util.PropsKeys; import com.liferay.sync.engine.util.PropsUtil; import com.liferay.sync.engine.util.PropsValues; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Shinn Lok */ public class BasePersistenceImpl<TT extends BaseModel, TID> extends BaseDaoImpl<TT, TID> implements BasePersistence<TT, TID> { public BasePersistenceImpl(Class<TT> clazz) throws SQLException { super(_getConnectionSource(), clazz); } @Override public int create(TT model) throws SQLException { int count = super.create(model); notifyModelListenersOnCreate(model); return count; } @Override public int createTable() throws SQLException { return TableUtils.createTable(connectionSource, dataClass); } @Override public int delete(TT model) throws SQLException { return delete(model, true); } public int delete(TT model, boolean notify) throws SQLException { int count = super.delete(model); if (notify) { notifyModelListenersOnRemove(model); } return count; } @Override public int deleteById(TID tid) throws SQLException { TT model = queryForId(tid); return delete(model, true); } public void registerModelListener(ModelListener<TT> modelListener) { _modelListeners.add(modelListener); } public void unregisterModelListener(ModelListener<TT> modelListener) { _modelListeners.remove(modelListener); } @Override public int update(TT targetModel) throws SQLException { TT sourceModel = queryForId(extractId(targetModel)); int count = super.update(targetModel); notifyModelListenersOnUpdate(sourceModel, targetModel); return count; } protected String[] getSyncNotificationFieldNames(String className) { String[] syncNotificationFieldNames = _syncNotificationFieldNames.get( className); if (syncNotificationFieldNames != null) { return syncNotificationFieldNames; } syncNotificationFieldNames = PropsUtil.getArray( PropsKeys.SYNC_NOTIFICATION_FIELD_NAMES_PREFIX + "." + className); _syncNotificationFieldNames.put(className, syncNotificationFieldNames); return syncNotificationFieldNames; } protected void notifyModelListenersOnCreate(TT model) { for (ModelListener<TT> modelListener : _modelListeners) { modelListener.onCreate(model); } } protected void notifyModelListenersOnRemove(TT model) { for (ModelListener<TT> modelListener : _modelListeners) { modelListener.onRemove(model); } } protected void notifyModelListenersOnUpdate(TT sourceModel, TT targetModel) throws SQLException { Map<String, Object> originalValues = new HashMap<>(); for (String syncNotificationFieldName : getSyncNotificationFieldNames(dataClass.getSimpleName())) { if (syncNotificationFieldName.isEmpty()) { continue; } FieldType fieldType = tableInfo.getFieldTypeByColumnName( syncNotificationFieldName); Object sourceFieldValue = fieldType.extractJavaFieldValue( sourceModel); Object targetFieldValue = fieldType.extractJavaFieldValue( targetModel); DataPersister dataPersister = fieldType.getDataPersister(); if (!dataPersister.dataIsEqual( sourceFieldValue, targetFieldValue)) { originalValues.put(fieldType.getColumnName(), sourceFieldValue); } } if (originalValues.isEmpty()) { return; } for (ModelListener<TT> modelListener : _modelListeners) { modelListener.onUpdate(targetModel, originalValues); } } private static ConnectionSource _getConnectionSource() throws SQLException { if (_connectionSource != null) { return _connectionSource; } StringBuilder sb = new StringBuilder(); sb.append("jdbc:h2:"); sb.append(PropsValues.SYNC_CONFIGURATION_DIRECTORY); FileSystem fileSystem = FileSystems.getDefault(); sb.append(fileSystem.getSeparator()); sb.append(PropsValues.SYNC_DATABASE_NAME); sb.append(";AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE;"); sb.append("LOCK_TIMEOUT=120000;MVCC=TRUE;"); _connectionSource = new JdbcPooledConnectionSource(sb.toString()); return _connectionSource; } private static ConnectionSource _connectionSource; private final List<ModelListener<TT>> _modelListeners = new ArrayList<>(); private final Map<String, String[]> _syncNotificationFieldNames = new HashMap<>(); }