me.icymint.libra.jdbc.xml.SqlXml Maven / Gradle / Ivy
package me.icymint.libra.jdbc.xml;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import me.icymint.libra.jdbc.JdbcAccessException;
import me.icymint.libra.jdbc.model.Column;
import me.icymint.libra.jdbc.model.Database;
import me.icymint.libra.jdbc.model.ForeignKey;
import me.icymint.libra.jdbc.model.Index;
import me.icymint.libra.jdbc.model.SqlFactory;
import me.icymint.libra.jdbc.model.SqlInfo;
import me.icymint.libra.jdbc.model.Table;
import me.icymint.libra.jdbc.model.Unique;
import me.icymint.libra.jdbc.query.TypeTransfer;
import me.icymint.libra.xml.AbstractDTDParser;
import me.icymint.libra.xml.XmlParser;
import me.icymint.libra.xml.XmlParserException;
import org.dom4j.Element;
/**
* DTD文件
*
* Apache DB项目所用的通用数据库ORM对象模型解析器。
*
* Libra-Jdbc项目的ORM模型采用了该方案。
*
* @author Daniel Yu
* @since 2013-3-12
*
*/
public class SqlXml extends AbstractDTDParser {
private class ColumnHolder {
private final boolean iskey;
private final Column c;
private ColumnHolder(Column c, boolean iskey) {
this.c = c;
this.iskey = iskey;
}
}
private static class SqlXmlHolder {
private final static SqlXml INSTANCE = new SqlXml();
}
private class TableHolder {
private final Collection fks;
private final Table t;
private TableHolder(Table t, Collection fks) {
this.t = t;
this.fks = fks;
}
}
public static XmlParser getInstance() {
return SqlXmlHolder.INSTANCE;
}
private SqlXml() {
super(SqlXml.class.getResource("database.dtd"),
"http://db.apache.org/torque/dtd/database.dtd", "database");
}
private boolean choseBoolean(boolean def, String src) {
String match = String.valueOf(!def);
if (src != null && match.equals(src)) {
return !def;
}
return def;
}
@Override
protected Database parser(Element root, SqlInfo info)
throws XmlParserException {
SqlFactory sf = SqlFactory.newInstance(info);
sf.getDatabase().setSchema(root.attributeValue("name"));
@SuppressWarnings("unchecked")
Iterator it = root.elementIterator("table");
Set fks = new LinkedHashSet();
while (it.hasNext()) {
fks.add(parserTable(it.next(), sf));
}
try {
for (TableHolder th : fks) {
for (ForeignKey fk : th.fks) {
th.t.addForeignKey(fk);
}
}
} catch (Exception e) {
throw new XmlParserException(e);
}
return sf.getDatabase();
}
private ColumnHolder parserColumn(Element next, SqlFactory sf)
throws XmlParserException {
String name = next.attributeValue("name");
String type = next.attributeValue("type").toUpperCase();
String size = next.attributeValue("size");
int length = -1;
if (size != null && !size.equals(""))
length = Integer.valueOf(size);
boolean notnull = choseBoolean(false, next.attributeValue("required"));
boolean primaryKey = choseBoolean(false,
next.attributeValue("primaryKey"));
boolean autoIncrement = choseBoolean(false,
next.attributeValue("autoIncrement"));
String defaultValue = next.attributeValue("default");
try {
return new ColumnHolder(sf.createColumn(name, TypeTransfer
.getInstance().reverse(type), length, notnull,
autoIncrement, defaultValue), primaryKey);
} catch (SQLException e) {
throw new XmlParserException(e);
}
}
private ForeignKey parserForeignKey(Element next, SqlFactory sf)
throws XmlParserException {
String ftable = next.attributeValue("foreignTable");
String local = null;
String foreign = null;
@SuppressWarnings("unchecked")
Iterator it = next.elementIterator("reference");
while (it.hasNext()) {
Element ie = it.next();
local = ie.attributeValue("local");
foreign = ie.attributeValue("foreign");
break;
}
if (local == null || foreign == null)
throw new XmlParserException("主外键未设置!");
return new ForeignKey(ftable, local, foreign);
}
private Index parserIndex(Element next, SqlFactory sf) {
String name = next.attributeValue("name");
@SuppressWarnings("unchecked")
Iterator it = next.elementIterator("index-column");
Set key = new LinkedHashSet();
while (it.hasNext()) {
key.add(it.next().attributeValue("name"));
}
return new Index(name, key.toArray(new String[] {}));
}
@SuppressWarnings("unchecked")
private TableHolder parserTable(Element next, SqlFactory sf)
throws XmlParserException {
Iterator it = next.elementIterator("column");
Set set = new LinkedHashSet();
Set key = new LinkedHashSet();
while (it.hasNext()) {
ColumnHolder ch = parserColumn(it.next(), sf);
set.add(ch.c);
if (ch.iskey)
key.add(ch.c.getName());
}
String name = next.attributeValue("name");
Table t;
try {
t = sf.createTable(name, key.toArray(new String[] {}),
set.toArray(new Column[] {}));
sf.getDatabase().addTable(t);
} catch (SQLException e) {
throw new XmlParserException(e);
}
it = next.elementIterator("index");
try {
while (it.hasNext()) {
t.addIndex(parserIndex(it.next(), sf));
}
} catch (SQLException e) {
throw new XmlParserException(e);
}
it = next.elementIterator("unique");
try {
while (it.hasNext()) {
t.addUnique(parserUnique(it.next(), sf));
}
} catch (SQLException e) {
throw new XmlParserException(e);
}
it = next.elementIterator("foreign-key");
Set fks = new LinkedHashSet();
while (it.hasNext()) {
fks.add(parserForeignKey(it.next(), sf));
}
return new TableHolder(t, fks);
}
private Unique parserUnique(Element next, SqlFactory sf) {
String name = next.attributeValue("name");
@SuppressWarnings("unchecked")
Iterator it = next.elementIterator("unique-column");
Set key = new LinkedHashSet();
while (it.hasNext()) {
key.add(it.next().attributeValue("name"));
}
return new Unique(name, key.toArray(new String[] {}));
}
@Override
protected void transfer(Element root, Database db)
throws XmlParserException {
if (db.getSchema() != null)
root.addAttribute("name", db.getSchema());
try {
for (Table t : db.getTables()) {
Element te = root.addElement("table");
te.addAttribute("name", t.getName());
for (Column c : t.getColumns()) {
Element ce = te.addElement("column");
ce.addAttribute("name", c.getName());
ce.addAttribute("type",
TypeTransfer.getInstance().query(c.getTypes()));
int length = c.getLength();
if (length > 0)
ce.addAttribute("size", String.valueOf(length));
Object o = c.getDefaultValue();
if (o != null)
ce.addAttribute("default", String.valueOf(o));
if (c.isAutoIncrement())
ce.addAttribute("autoIncrement", "true");
if (c.isNotNull())
ce.addAttribute("required", "true");
if (t.getKeys().contains(c))
ce.addAttribute("primaryKey", "true");
}
for (Index i : t.getIndexes()) {
Element ie = te.addElement("index");
ie.addAttribute("name", i.getName());
for (String v : i.getColumns()) {
ie.addElement("index-column").addAttribute("name", v);
}
}
for (Unique i : t.getUniques()) {
Element ie = te.addElement("unique");
ie.addAttribute("name", i.getName());
for (String v : i.getColumns()) {
ie.addElement("unique-column").addAttribute("name", v);
}
}
for (ForeignKey fk : t.getForeignKeys()) {
Element ie = te.addElement("foreign-key");
ie.addAttribute("foreignTable", fk.foreignTable());
Element xx = ie.addElement("reference");
xx.addAttribute("local", fk.getLocalColumn());
xx.addAttribute("foreign", fk.getForeignColumn());
}
}
} catch (JdbcAccessException e) {
throw new XmlParserException(e);
}
}
}