package org.springframework.roo.addon.dbre.addon.model;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Stack;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.roo.addon.dbre.addon.model.DatabaseXmlUtils.IndexType;
import org.springframework.roo.model.JavaPackage;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* {@link ContentHandler} implementation for converting the DBRE XML file into a
* {@link Database} object.
*
* @author Alan Stewart
* @author Juan Carlos GarcĂa
* @since 1.1
*/
public class DatabaseContentHandler extends DefaultHandler {
private Database database;
private JavaPackage destinationPackage;
private boolean disableGeneratedIdentifiers;
private boolean disableVersionFields;
private boolean includeNonPortableAttributes;
private String moduleName;
private boolean repository;
private boolean service;
private final Stack<Object> stack = new Stack<Object>();
private final Set<Table> tables = new LinkedHashSet<Table>();
private boolean testAutomatically;
/**
* Constructor
*/
public DatabaseContentHandler() {
super();
}
@Override
public void endElement(final String uri, final String localName, final String qName)
throws SAXException {
final Object tmp = stack.pop();
if (qName.equals("option")) {
final Option option = (Option) tmp;
if (stack.peek() instanceof ForeignKey) {
if (option.getKey().equals("exported")) {
((ForeignKey) stack.peek()).setExported(Boolean.parseBoolean(option.getValue()));
}
if (option.getKey().equals("foreignSchemaName")) {
((ForeignKey) stack.peek()).setForeignSchemaName(option.getValue());
}
}
if (option.getKey().equals("moduleName")) {
moduleName = option.getValue();
}
if (option.getKey().equals("includeNonPortableAttributes")) {
includeNonPortableAttributes = Boolean.parseBoolean(option.getValue());
}
if (option.getKey().equals("disableVersionFields")) {
disableVersionFields = Boolean.parseBoolean(option.getValue());
}
if (option.getKey().equals("disableGeneratedIdentifiers")) {
disableGeneratedIdentifiers = Boolean.parseBoolean(option.getValue());
}
if (option.getKey().equals("repository")) {
repository = Boolean.parseBoolean(option.getValue());
}
if (option.getKey().equals("service")) {
service = Boolean.parseBoolean(option.getValue());
}
if (option.getKey().equals("testAutomatically")) {
testAutomatically = Boolean.parseBoolean(option.getValue());
}
} else if (qName.equals("table")) {
tables.add((Table) tmp);
} else if (qName.equals("column")) {
((Table) stack.peek()).addColumn((Column) tmp);
} else if (qName.equals("foreign-key")) {
final ForeignKey foreignKey = (ForeignKey) tmp;
final Table table = (Table) stack.peek();
if (foreignKey.isExported()) {
table.addExportedKey(foreignKey);
} else {
table.addImportedKey(foreignKey);
}
} else if (qName.equals("reference")) {
((ForeignKey) stack.peek()).addReference((Reference) tmp);
} else if (qName.equals("unique") || qName.equals("index")) {
((Table) stack.peek()).addIndex((Index) tmp);
} else if (qName.equals("unique-column") || qName.equals("index-column")) {
((Index) stack.peek()).addColumn((IndexColumn) tmp);
} else if (qName.equals("database")) {
database = new Database(tables);
database.setModuleName(moduleName);
database.setDestinationPackage(destinationPackage);
database.setIncludeNonPortableAttributes(includeNonPortableAttributes);
database.setDisableVersionFields(disableVersionFields);
database.setDisableGeneratedIdentifiers(disableGeneratedIdentifiers);
database.setRepository(repository);
database.setService(service);
database.setTestAutomatically(testAutomatically);
} else {
stack.push(tmp);
}
}
public Database getDatabase() {
return database;
}
@Override
public void startElement(final String uri, final String localName, final String qName,
final Attributes attributes) throws SAXException {
if (qName.equals("database")) {
stack.push(new Object());
if (StringUtils.isNotBlank(attributes.getValue("package"))) {
destinationPackage = new JavaPackage(attributes.getValue("package"));
}
} else if (qName.equals("option")) {
stack.push(new Option(attributes.getValue("key"), attributes.getValue("value")));
} else if (qName.equals("table")) {
stack.push(getTable(attributes));
} else if (qName.equals("column")) {
stack.push(getColumn(attributes));
} else if (qName.equals("foreign-key")) {
stack.push(getForeignKey(attributes));
} else if (qName.equals("reference")) {
stack.push(getReference(attributes));
} else if (qName.equals("unique")) {
stack.push(getIndex(attributes, IndexType.UNIQUE));
} else if (qName.equals("index")) {
stack.push(getIndex(attributes, IndexType.INDEX));
} else if (qName.equals("unique-column") || qName.equals("index-column")) {
stack.push(getIndexColumn(attributes));
}
}
private Column getColumn(final Attributes attributes) {
final String type = attributes.getValue("type");
final String[] dataTypeAndName = StringUtils.split(type, ",");
Validate
.notNull(
dataTypeAndName,
"The 'type' attribute of the column element must contain a comma separated value pair, eg, type=\"12,varchar\"."
+ getErrorMessage());
final int dataType = Integer.parseInt(dataTypeAndName[0]);
final String typeName = dataTypeAndName[1];
int columnSize;
int scale = 0;
final String size = attributes.getValue("size");
if (size.contains(",")) {
final String[] precisionScale = StringUtils.split(size, ",");
columnSize = Integer.parseInt(precisionScale[0]);
scale = Integer.parseInt(precisionScale[1]);
} else {
columnSize = Integer.parseInt(size);
}
if (StringUtils.isNotBlank(attributes.getValue("scale"))) {
scale = Integer.parseInt(attributes.getValue("scale"));
}
final Column column =
new Column(attributes.getValue(DatabaseXmlUtils.NAME), dataType, typeName, columnSize,
scale);
column.setDescription(attributes.getValue(DatabaseXmlUtils.DESCRIPTION));
column.setPrimaryKey(Boolean.parseBoolean(attributes.getValue("primaryKey")));
column.setRequired(Boolean.parseBoolean(attributes.getValue("required")));
return column;
}
private String getErrorMessage() {
return "Your DBRE XML file may be not be in the current format. Delete the file and execute the database reverse engineer command again.";
}
private ForeignKey getForeignKey(final Attributes attributes) {
final ForeignKey foreignKey =
new ForeignKey(attributes.getValue(DatabaseXmlUtils.NAME),
attributes.getValue(DatabaseXmlUtils.FOREIGN_TABLE));
foreignKey.setOnDelete(CascadeAction.getCascadeAction(attributes
.getValue(DatabaseXmlUtils.ON_DELETE)));
foreignKey.setOnUpdate(CascadeAction.getCascadeAction(attributes
.getValue(DatabaseXmlUtils.ON_UPDATE)));
return foreignKey;
}
private Index getIndex(final Attributes attributes, final IndexType indexType) {
final Index index = new Index(attributes.getValue(DatabaseXmlUtils.NAME));
index.setUnique(indexType == IndexType.UNIQUE);
return index;
}
private IndexColumn getIndexColumn(final Attributes attributes) {
return new IndexColumn(attributes.getValue(DatabaseXmlUtils.NAME));
}
private Reference getReference(final Attributes attributes) {
return new Reference(attributes.getValue(DatabaseXmlUtils.LOCAL),
attributes.getValue(DatabaseXmlUtils.FOREIGN));
}
private Table getTable(final Attributes attributes) {
final Table table =
new Table(attributes.getValue(DatabaseXmlUtils.NAME), new Schema(
attributes.getValue("alias")));
if (StringUtils.isNotBlank(attributes.getValue(DatabaseXmlUtils.DESCRIPTION))) {
table.setDescription(DatabaseXmlUtils.DESCRIPTION);
}
return table;
}
private static class Option extends Pair<String, String> {
private static final long serialVersionUID = 3471455277824528758L;
private final String key;
private final String value;
public Option(final String key, final String value) {
this.key = key;
this.value = value;
}
@Override
public String getLeft() {
return key;
}
@Override
public String getRight() {
return value;
}
@Override
public String setValue(final String value) {
throw new UnsupportedOperationException();
}
}
}