¶Ô±ÈÐÂÎļþ |
| | |
| | | /* 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. |
| | | */ |
| | | package org.flowable.common.engine.impl.db; |
| | | |
| | | import liquibase.Liquibase; |
| | | import liquibase.database.Database; |
| | | import liquibase.database.DatabaseConnection; |
| | | import liquibase.database.DatabaseFactory; |
| | | import liquibase.database.jvm.JdbcConnection; |
| | | import liquibase.exception.DatabaseException; |
| | | import liquibase.resource.ClassLoaderResourceAccessor; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.flowable.common.engine.api.FlowableException; |
| | | import org.flowable.common.engine.impl.AbstractEngineConfiguration; |
| | | import org.flowable.common.engine.impl.context.Context; |
| | | import org.flowable.common.engine.impl.interceptor.CommandContext; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.sql.Connection; |
| | | import java.sql.SQLException; |
| | | |
| | | /** |
| | | * @author Filip Hrisafov |
| | | */ |
| | | public abstract class LiquibaseBasedSchemaManager implements SchemaManager { |
| | | |
| | | protected final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | protected final String context; |
| | | protected final String changeLogFile; |
| | | protected final String changeLogPrefix; |
| | | |
| | | public LiquibaseBasedSchemaManager(String context, String changeLogFile, String changeLogPrefix) { |
| | | this.context = context; |
| | | this.changeLogFile = changeLogFile; |
| | | this.changeLogPrefix = changeLogPrefix; |
| | | } |
| | | |
| | | public void initSchema(String databaseSchemaUpdate) { |
| | | try { |
| | | if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP.equals(databaseSchemaUpdate)) { |
| | | schemaCreate(); |
| | | |
| | | } else if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE.equals(databaseSchemaUpdate)) { |
| | | schemaDrop(); |
| | | schemaCreate(); |
| | | |
| | | } else if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE.equals(databaseSchemaUpdate)) { |
| | | schemaUpdate(); |
| | | |
| | | } else if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_FALSE.equals(databaseSchemaUpdate)) { |
| | | //åæ¶èªæ£æ¥ |
| | | //schemaCheckVersion(); |
| | | } |
| | | } catch (Exception e) { |
| | | throw new FlowableException("Error initialising " + context + " data model", e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void schemaCreate() { |
| | | Liquibase liquibase = null; |
| | | try { |
| | | liquibase = createLiquibaseInstance(getDatabaseConfiguration()); |
| | | liquibase.update(context); |
| | | } catch (Exception e) { |
| | | throw new FlowableException("Error creating " + context + " engine tables", e); |
| | | } finally { |
| | | closeDatabase(liquibase); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void schemaDrop() { |
| | | Liquibase liquibase = null; |
| | | try { |
| | | liquibase = createLiquibaseInstance(getDatabaseConfiguration()); |
| | | liquibase.dropAll(); |
| | | } catch (Exception e) { |
| | | throw new FlowableException("Error dropping " + context + " engine tables", e); |
| | | } finally { |
| | | closeDatabase(liquibase); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public String schemaUpdate() { |
| | | Liquibase liquibase = null; |
| | | try { |
| | | liquibase = createLiquibaseInstance(getDatabaseConfiguration()); |
| | | liquibase.update(context); |
| | | } catch (Exception e) { |
| | | throw new FlowableException("Error updating " + context + " engine tables", e); |
| | | } finally { |
| | | closeDatabase(liquibase); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public void schemaCheckVersion() { |
| | | Liquibase liquibase = null; |
| | | try { |
| | | liquibase = createLiquibaseInstance(getDatabaseConfiguration()); |
| | | liquibase.validate(); |
| | | } catch (Exception e) { |
| | | throw new FlowableException("Error validating " + context + " engine schema", e); |
| | | } finally { |
| | | closeDatabase(liquibase); |
| | | } |
| | | } |
| | | |
| | | protected abstract LiquibaseDatabaseConfiguration getDatabaseConfiguration(); |
| | | |
| | | protected Liquibase createLiquibaseInstance(LiquibaseDatabaseConfiguration databaseConfiguration) throws SQLException { |
| | | Connection jdbcConnection = null; |
| | | boolean closeConnection = false; |
| | | try { |
| | | CommandContext commandContext = Context.getCommandContext(); |
| | | if (commandContext == null) { |
| | | jdbcConnection = databaseConfiguration.getDataSource().getConnection(); |
| | | closeConnection = true; |
| | | } else { |
| | | jdbcConnection = commandContext.getSession(DbSqlSession.class).getSqlSession().getConnection(); |
| | | } |
| | | |
| | | // A commit is needed here, because one of the things that Liquibase does when acquiring its lock |
| | | // is doing a rollback, which removes all changes done so far. |
| | | // For most databases, this is not a problem as DDL statements are not transactional. |
| | | // However for some (e.g. sql server), this would remove all previous statements, which is not wanted, |
| | | // hence the extra commit here. |
| | | if (!jdbcConnection.getAutoCommit()) { |
| | | jdbcConnection.commit(); |
| | | } |
| | | |
| | | DatabaseConnection connection = new JdbcConnection(jdbcConnection); |
| | | Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection); |
| | | database.setDatabaseChangeLogTableName(changeLogPrefix + database.getDatabaseChangeLogTableName()); |
| | | database.setDatabaseChangeLogLockTableName(changeLogPrefix + database.getDatabaseChangeLogLockTableName()); |
| | | |
| | | String databaseSchema = databaseConfiguration.getDatabaseSchema(); |
| | | if (StringUtils.isNotEmpty(databaseSchema)) { |
| | | database.setDefaultSchemaName(databaseSchema); |
| | | database.setLiquibaseSchemaName(databaseSchema); |
| | | } |
| | | |
| | | String databaseCatalog = databaseConfiguration.getDatabaseCatalog(); |
| | | if (StringUtils.isNotEmpty(databaseCatalog)) { |
| | | database.setDefaultCatalogName(databaseCatalog); |
| | | database.setLiquibaseCatalogName(databaseCatalog); |
| | | } |
| | | |
| | | return new Liquibase(changeLogFile, new ClassLoaderResourceAccessor(), database); |
| | | |
| | | } catch (Exception e) { |
| | | // We only close the connection if an exception occurred, otherwise the Liquibase instance cannot be used |
| | | if (jdbcConnection != null && closeConnection) { |
| | | jdbcConnection.close(); |
| | | } |
| | | throw new FlowableException("Error creating " + context + " liquibase instance", e); |
| | | } |
| | | } |
| | | |
| | | protected void closeDatabase(Liquibase liquibase) { |
| | | if (liquibase != null) { |
| | | Database database = liquibase.getDatabase(); |
| | | if (database != null) { |
| | | // do not close the shared connection if a command context is currently active |
| | | if (Context.getCommandContext() == null) { |
| | | try { |
| | | database.close(); |
| | | } catch (DatabaseException e) { |
| | | logger.warn("Error closing database for {}", context, e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |