/* 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.riotfamily.revolt;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.riotfamily.revolt.definition.Table;
import org.riotfamily.revolt.support.DatabaseUtils;
import org.riotfamily.revolt.support.LogTable;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
/**
* @author Felix Gnass [fgnass at neteye dot de]
*/
public class EvolutionHistory implements BeanNameAware {
private String[] depends = new String[0];
private String moduleName;
private String checkTableName;
private List<ChangeSet> changeSets;
private LogTable logTable;
private ArrayList<String> appliedIds;
public void setBeanName(String name) {
this.moduleName = name;
}
/**
* Sets the name of a table that, if it exists, indicates that the module
* is already installed. The check is performed when the history contains
* only one change-set in order to determine whether the module was
* installed before. In case of a fresh install (check-table not found),
* no changes are performed and the change-set are marked as applied.
* <p>
* Use the name of a table that exits <em>before</em> any change-set is
* applied. It's okay when that table is renamed or dropped later.
* When no table name is set, all changes are performed that have not been
* marked as applied.
* </p>
*/
public void setCheckTableName(String checkTableName) {
this.checkTableName = checkTableName;
}
public String getModuleName() {
return this.moduleName;
}
public void setChangeSets(ChangeSet[] changeSets) {
this.changeSets = new ArrayList<ChangeSet>();
for (int i = 0; i < changeSets.length; i++) {
ChangeSet changeSet = changeSets[i];
changeSet.setHistory(this);
changeSet.setSequenceNumber(i);
this.changeSets.add(changeSet);
}
}
/**
* Initializes the history from the given log-table.
*/
public void init(LogTable logTable, SimpleJdbcTemplate template) {
this.logTable = logTable;
appliedIds = new ArrayList<String>();
appliedIds.addAll(logTable.getAppliedChangeSetIds(moduleName));
}
private boolean isModuleAlreadyInstalled(SimpleJdbcTemplate template) {
if (!appliedIds.isEmpty()) {
// Some changes have already been applied
return true;
}
return checkTableName == null || DatabaseUtils.tableExists(template.getJdbcOperations(), new Table(checkTableName));
}
/**
* Returns a script that needs to be executed in order update the schema.
*/
public Script getScript(Dialect dialect, SimpleJdbcTemplate template) {
if (isModuleAlreadyInstalled(template)) {
return getMigrationScript(dialect, template);
}
else {
return getInitScript(template);
}
}
private Script getInitScript(SimpleJdbcTemplate template) {
Script script = new Script();
for (ChangeSet changeSet : changeSets) {
script.append(markAsApplied(changeSet, template));
}
return script;
}
private Script getMigrationScript(Dialect dialect, SimpleJdbcTemplate template) {
Script script = new Script();
for (ChangeSet changeSet : changeSets) {
if (!isApplied(changeSet)) {
script.append(changeSet.getScript(dialect, template));
script.append(markAsApplied(changeSet, template));
}
}
return script;
}
/**
* Returns whether the given changeSet has already been applied.
*/
private boolean isApplied(ChangeSet changeSet) {
return appliedIds.contains(changeSet.getId());
}
/**
* Returns a script that can be used to add an entry to the log-table that
* marks the given ChangeSet as applied.
*/
private Script markAsApplied(ChangeSet changeSet, SimpleJdbcTemplate template) {
appliedIds.add(changeSet.getId());
return logTable.getInsertScript(changeSet);
}
public void setDepends(String[] depends) {
this.depends = depends;
}
public boolean dependsOn(EvolutionHistory history) {
return Arrays.asList(depends).contains(history.getModuleName());
}
}