/* 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.config;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.riotfamily.revolt.ChangeSet;
import org.riotfamily.revolt.EvolutionException;
import org.riotfamily.revolt.EvolutionHistory;
import org.riotfamily.revolt.Refactoring;
import org.riotfamily.revolt.definition.Column;
import org.riotfamily.revolt.definition.ForeignKey;
import org.riotfamily.revolt.definition.Index;
import org.riotfamily.revolt.definition.RecordEntry;
import org.riotfamily.revolt.definition.Reference;
import org.riotfamily.revolt.definition.UniqueConstraint;
import org.riotfamily.revolt.definition.UpdateStatement;
import org.riotfamily.revolt.refactor.AddColumn;
import org.riotfamily.revolt.refactor.AddForeignKey;
import org.riotfamily.revolt.refactor.AddUniqueConstraint;
import org.riotfamily.revolt.refactor.CreateAutoIncrementSequence;
import org.riotfamily.revolt.refactor.CreateIndex;
import org.riotfamily.revolt.refactor.CreateTable;
import org.riotfamily.revolt.refactor.DropColumn;
import org.riotfamily.revolt.refactor.DropConstraint;
import org.riotfamily.revolt.refactor.DropForeignKey;
import org.riotfamily.revolt.refactor.DropIndex;
import org.riotfamily.revolt.refactor.DropTable;
import org.riotfamily.revolt.refactor.ExecSql;
import org.riotfamily.revolt.refactor.InsertData;
import org.riotfamily.revolt.refactor.ModifyColumn;
import org.riotfamily.revolt.refactor.RenameColumn;
import org.riotfamily.revolt.refactor.RenameTable;
import org.riotfamily.revolt.refactor.UpdateData;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* NamespaceHandler that handles the <code>revolt</code>
* namspace as defined in <code>revolt.xsd</code> which can be found in
* the same package.
*/
public class RevoltNamespaceHandler implements NamespaceHandler {
public void init() {
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
if (DomUtils.nodeNameEquals(element, "history")) {
RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(EvolutionHistory.class);
MutablePropertyValues pv = new MutablePropertyValues();
pv.addPropertyValue("changeSets", parseChangeSets(element));
pv.addPropertyValue("checkTableName", element.getAttribute("check-table-name"));
String depends = element.getAttribute("depends");
if (depends != null) {
pv.addPropertyValue("depends",
StringUtils.tokenizeToStringArray(depends, ","));
}
definition.setPropertyValues(pv);
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, element.getAttribute("module"));
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
return definition;
}
throw new IllegalArgumentException(
"Expected <history> but found: " + element.getNodeName());
}
private List<ChangeSet> parseChangeSets(Element element) {
ArrayList<ChangeSet> changeSets = new ArrayList<ChangeSet>();
Iterator<Element> it = DomUtils.getChildElementsByTagName(element, "change-set").iterator();
while (it.hasNext()) {
Element ele = it.next();
changeSets.add(new ChangeSet(ele.getAttribute("id"), parseRefactorings(ele)));
}
return changeSets;
}
@SuppressWarnings("unchecked")
private List<Refactoring> parseRefactorings(Element element) {
ManagedList refactorings = new ManagedList();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if (child instanceof Element) {
Refactoring refactoring = parseRefactoring((Element) child);
if (refactoring != null) {
refactorings.add(refactoring);
}
}
}
return refactorings;
}
private Refactoring parseRefactoring(Element ele) {
if (DomUtils.nodeNameEquals(ele, "add-column")) {
return new AddColumn(ele.getAttribute("table"),
parseColumn(ele));
}
if (DomUtils.nodeNameEquals(ele, "add-foreign-key")) {
return new AddForeignKey(ele.getAttribute("table"),
new ForeignKey(ele.getAttribute("name"),
ele.getAttribute("references"),
parseReferences(ele),
parseOnDelete(ele),
parseOnUpdate(ele)));
}
if (DomUtils.nodeNameEquals(ele, "add-unique-constraint")) {
return new AddUniqueConstraint(ele.getAttribute("table"),
new UniqueConstraint(ele.getAttribute("name"),
StringUtils.tokenizeToStringArray(ele.getAttribute("on"), ",")));
}
if (DomUtils.nodeNameEquals(ele, "create-index")) {
return new CreateIndex(ele.getAttribute("table"),
new Index(ele.getAttribute("name"),
StringUtils.tokenizeToStringArray(ele.getAttribute("on"), ","),
Boolean.valueOf(ele.getAttribute("unique")).booleanValue()));
}
if (DomUtils.nodeNameEquals(ele, "create-table")) {
return new CreateTable(ele.getAttribute("name"),
parseColumns(ele));
}
if (DomUtils.nodeNameEquals(ele, "drop-column")) {
return new DropColumn(ele.getAttribute("table"),
ele.getAttribute("column"));
}
if (DomUtils.nodeNameEquals(ele, "drop-foreign-key")) {
return new DropForeignKey(ele.getAttribute("table"),
ele.getAttribute("foreign-key"));
}
if (DomUtils.nodeNameEquals(ele, "drop-index")) {
return new DropIndex(ele.getAttribute("table"),
ele.getAttribute("index"));
}
if (DomUtils.nodeNameEquals(ele, "drop-table")) {
return new DropTable(ele.getAttribute("table"),
Boolean.valueOf(ele.getAttribute("cascade")).booleanValue());
}
if (DomUtils.nodeNameEquals(ele, "drop-constraint")) {
return new DropConstraint(ele.getAttribute("table"),
ele.getAttribute("constraint"));
}
if (DomUtils.nodeNameEquals(ele, "modify-column")) {
return new ModifyColumn(ele.getAttribute("table"),
parseColumn(ele));
}
if (DomUtils.nodeNameEquals(ele, "rename-column")) {
return new RenameColumn(ele.getAttribute("table"),
ele.getAttribute("column"), ele.getAttribute("rename-to"));
}
if (DomUtils.nodeNameEquals(ele, "rename-table")) {
return new RenameTable(ele.getAttribute("table"),
ele.getAttribute("rename-to"));
}
if (DomUtils.nodeNameEquals(ele, "insert-data")) {
return new InsertData(ele.getAttribute("table"),
parseEntries(ele));
}
if (DomUtils.nodeNameEquals(ele, "update-data")) {
return new UpdateData(parseUpdateStatements(ele));
}
if (DomUtils.nodeNameEquals(ele, "exec-sql")) {
return new ExecSql(ele.getTextContent());
}
if (DomUtils.nodeNameEquals(ele, "create-auto-increment-seq")) {
return new CreateAutoIncrementSequence(
ele.getAttribute("name"));
}
if (DomUtils.nodeNameEquals(ele, "custom")) {
try {
return (Refactoring) Class.forName(ele.getAttribute("class")).newInstance();
}
catch (Exception e) {
throw new EvolutionException("Error creating custom refactoring", e);
}
}
throw new EvolutionException("Unsupported refactoring: " + ele.getNodeName());
}
private String parseOnUpdate(Element ele) {
Element e = DomUtils.getChildElementByTagName(ele, "on-update");
return e != null ? e.getAttribute("value") : null;
}
private String parseOnDelete(Element ele) {
Element e = DomUtils.getChildElementByTagName(ele, "on-delete");
return e != null ? e.getAttribute("value") : null;
}
private List<Column> parseColumns(Element ele) {
ArrayList<Column> columns = new ArrayList<Column>();
Iterator<Element> it = DomUtils.getChildElementsByTagName(ele, "column").iterator();
while (it.hasNext()) {
columns.add(parseColumn(it.next()));
}
return columns;
}
private Column parseColumn(Element ele) {
Column column = new Column();
column.setName(ele.getAttribute("name"));
if (StringUtils.hasLength(ele.getAttribute("type"))) {
column.setType(ele.getAttribute("type"));
}
if (StringUtils.hasLength(ele.getAttribute("length"))) {
column.setLength(Integer.valueOf(
ele.getAttribute("length")).intValue());
}
if (StringUtils.hasLength(ele.getAttribute("primary-key"))) {
column.setPrimaryKey(Boolean.valueOf(
ele.getAttribute("primary-key")).booleanValue());
}
if (StringUtils.hasLength(ele.getAttribute("not-null"))) {
column.setNotNull(Boolean.valueOf(
ele.getAttribute("not-null")).booleanValue());
}
if (StringUtils.hasLength(ele.getAttribute("auto-increment"))) {
column.setAutoIncrement(Boolean.valueOf(
ele.getAttribute("auto-increment")).booleanValue());
}
if (StringUtils.hasLength(ele.getAttribute("default-value"))) {
column.setDefaultValue(ele.getAttribute("default-value"));
}
return column;
}
private List<Reference> parseReferences(Element ele) {
ArrayList<Reference> references = new ArrayList<Reference>();
Iterator<Element> it = DomUtils.getChildElementsByTagName(ele, "ref").iterator();
while (it.hasNext()) {
Element e = it.next();
references.add(new Reference(
e.getAttribute("local"),
e.getAttribute("foreign")));
}
return references;
}
private List<RecordEntry> parseEntries(Element ele) {
ArrayList<RecordEntry> entries = new ArrayList<RecordEntry>();
Iterator<Element> it = DomUtils.getChildElementsByTagName(ele, "entry").iterator();
while (it.hasNext()) {
Element e = it.next();
entries.add(new RecordEntry(
e.getAttribute("column"),
e.getAttribute("value")));
}
return entries;
}
private List<UpdateStatement> parseUpdateStatements(Element ele) {
ArrayList<UpdateStatement> statements = new ArrayList<UpdateStatement>();
Iterator<Element> it = DomUtils.getChildElementsByTagName(ele, "statement").iterator();
while (it.hasNext()) {
Element e = it.next();
statements.add(new UpdateStatement(
e.getAttribute("dialects"),
e.getAttribute("sql")));
}
return statements;
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder
holder, ParserContext parserContext) {
throw new UnsupportedOperationException(
"Bean decoration is not supported.");
}
}