while (tableInfo.next())
{
logger.debug("TABLE: " + tableInfo);
Entity e = new Entity();
e.setName(tableInfo.getString("TABLE_NAME"));
m.getEntities().add(e);
// ADD THE COLUMNS
ResultSet fieldInfo = md.getColumns(SCHEMA_NAME, null, tableInfo.getString("TABLE_NAME"), null);
while (fieldInfo.next())
{
logger.debug("COLUMN: " + fieldInfo);
Field f = new Field();
f.setName(fieldInfo.getString("COLUMN_NAME"));
f.setType(Field.Type.getType(fieldInfo.getInt("DATA_TYPE")));
f.setDefaultValue(fieldInfo.getString("COLUMN_DEF"));
if (md.getDatabaseProductName().toLowerCase().contains("mysql"))
{
// accomodate mysql CURRENT_TIMESTAMP
if ("CURRENT_TIMESTAMP".equals(f.getDefaultValue())
&& (f.getType().equals(Field.Type.DATETIME) || f.getType().equals(Field.Type.DATE)))
{
f.setDefaultValue(null);
f.setAuto(true);
}
// accomodate mysql text/string fields +
// nillable="false" -> mysql ignore not null and so
// should we!
}
if (fieldInfo.getString("REMARKS") != null && !"".equals(fieldInfo.getString("REMARKS").trim())) f
.setDescription(fieldInfo.getString("REMARKS"));
if (fieldInfo.getBoolean("NULLABLE")) f.setNillable(true);
// auto increment?
if (f.getType().equals(Field.Type.INT))
{
if (fieldInfo.getObject("IS_AUTOINCREMENT") != null) f.setAuto(fieldInfo
.getBoolean("IS_AUTOINCREMENT"));
}
if (f.getType().equals(Field.Type.STRING) || f.getType().equals(Field.Type.CHAR))
{
if (fieldInfo.getInt("COLUMN_SIZE") > 255)
{
f.setType(Field.Type.TEXT);
f.setLength(fieldInfo.getInt("COLUMN_SIZE"));
}
else
{
if (fieldInfo.getInt("COLUMN_SIZE") != 255) f.setLength(fieldInfo.getInt("COLUMN_SIZE"));
f.setType(null); // defaults to string
}
}
ResultSet xrefInfo = md.getImportedKeys(SCHEMA_NAME, null, tableInfo.getString("TABLE_NAME"));
while (xrefInfo.next())
{
if (xrefInfo.getString("FKCOLUMN_NAME").equals(fieldInfo.getString("COLUMN_NAME")))
{
f.setType(Field.Type.XREF_SINGLE);
// problem: PKTABLE_NAME is lowercase, need to be
// corrected later?
f.setXrefField(xrefInfo.getString("PKTABLE_NAME") + "."
+ xrefInfo.getString("PKCOLUMN_NAME"));
}
}
e.getFields().add(f);
}
// GET AUTO INCREMENT
// mysql workaround
Statement stmt = null;
try
{
String sql = "select * from " + e.getName() + " where 1=0";
stmt = conn.createStatement();
ResultSet autoincRs = stmt.executeQuery(sql);
ResultSetMetaData rowMeta = autoincRs.getMetaData();
for (int i = 1; i <= rowMeta.getColumnCount(); i++)
{
if (rowMeta.isAutoIncrement(i))
{
e.getFields().get(i - 1).setAuto(true);
}
}
}
catch (Exception exc)
{
logger.error("didn't retrieve autoinc/sequence: " + exc.getMessage());
// e.printStackTrace();
}
finally
{
stmt.close();
}
// ADD UNIQUE CONTRAINTS
ResultSet rsIndex = md.getIndexInfo(SCHEMA_NAME, null, tableInfo.getString("TABLE_NAME"), true, false);
// indexed list of uniques
Map<String, List<String>> uniques = new LinkedHashMap<String, List<String>>();
while (rsIndex.next())
{
logger.debug("UNIQUE: " + rsIndex);
// TABLE_CAT='molgenistest' TABLE_SCHEM='null'
// TABLE_NAME='boolentity' NON_UNIQUE='false'
// INDEX_QUALIFIER='' INDEX_NAME='PRIMARY' TYPE='3'
// ORDINAL_POSITION='1' COLUMN_NAME='id' ASC_OR_DESC='A'
// CARDINALITY='0' PAGES='0' FILTER_CONDITION='null'
if (uniques.get(rsIndex.getString("INDEX_NAME")) == null) uniques.put(
rsIndex.getString("INDEX_NAME"), new ArrayList<String>());
uniques.get(rsIndex.getString("INDEX_NAME")).add(rsIndex.getString("COLUMN_NAME"));
}
for (List<String> index : uniques.values())
{
if (index.size() == 1)
{
e.getField(index.get(0)).setUnique(true);
}
else
{
StringBuilder fieldsBuilder = new StringBuilder();
for (String field_name : index)
{
fieldsBuilder.append(',').append(field_name);
}
Unique u = new Unique();
u.setFields(fieldsBuilder.substring(1));
e.getUniques().add(u);
}
}
// FIND type="autoid"
for (Field f : e.getFields())
{
if (f.getAuto() != null && f.getAuto() && f.getType().equals(Type.INT) && f.getUnique() != null
&& f.getUnique())
{
f.setType(Field.Type.AUTOID);
f.setAuto(null);
f.setUnique(null);
}
}
}
// GUESS type="xref"
// normally they should be defined as foreign key but sometimes
// designers leave this out
// rule: if the field name is the same and one is autoid,
// then other fields having the same name are likely to be xref to
// the autoid
for (Entity e : m.getEntities())
{
for (Field f : e.getFields())
{
if (Field.Type.AUTOID.equals(f.getType()))
{
for (Entity otherE : m.getEntities())
{
for (Field otherF : otherE.getFields())
{
// assume xref if
// name == name
// otherF.type == int
if (otherF.getName().equals(f.getName()) && otherF.getType().equals(Field.Type.INT))
{
logger.debug("Guessed that " + otherE.getName() + "." + otherF.getName()
+ " references " + e.getName() + "." + f.getName());
otherF.setType(Field.Type.XREF_SINGLE);
// otherF.setXrefEntity(;
otherF.setXrefField(e.getName() + "." + f.getName());
}
}
}
}
}
}
// GUESS the xref labels
// guess the xreflabel as being the non-autoid field that is unique
// and not null
// rule: if there is another unique field in the referenced table
// then that probably is usable as label
for (Entity e : m.getEntities())
{
for (Field f : e.getFields())
{
if (Field.Type.XREF_SINGLE.equals(f.getType()))
{
String xrefEntityName = f.getXrefField().substring(0, f.getXrefField().indexOf("."));
String xrefFieldName = f.getXrefField().substring(f.getXrefField().indexOf(".") + 1);
// reset the xref entity to the uppercase version
f.setXrefField(m.getEntity(xrefEntityName).getName() + "." + xrefFieldName);
for (Field labelField : m.getEntity(xrefEntityName).getFields())
{
// find the other unique, nillable="false" field, if
// any
if (!labelField.getName().equals(xrefFieldName)
&& Boolean.TRUE.equals(labelField.getUnique())
&& Boolean.FALSE.equals(labelField.getNillable()))
{
logger.debug("guessed label " + e.getName() + "." + labelField.getName());
f.setXrefLabel(labelField.getName());
}
}
}
}
}
// GUESS the inheritance relationship
// rule: if there is a foreign key that is unique itself it is
// probably inheriting...
// action: change to inheritance and remove the xref field
for (Entity e : m.getEntities())
{
List<Field> toBeRemoved = new ArrayList<Field>();
for (Field f : e.getFields())
{
if (Field.Type.XREF_SINGLE.equals(f.getType()) && Boolean.TRUE.equals(f.getUnique()))
{
String entityName = f.getXrefField().substring(0, f.getXrefField().indexOf("."));
e.setExtends(entityName);
toBeRemoved.add(f);
}
}
for (Field f : toBeRemoved)
{
e.getFields().remove(f);
}
}
// TODO GUESS the type="mref"
// rule: any entity that is not a subclass and that has maximum two
// xref fields and autoid field
// should be a mref
List<Entity> toBeRemoved = new ArrayList<Entity>();
for (Entity e : m.getEntities())
if ("".equals(e.getExtends()))
{
if (e.getFields().size() <= 3)
{
int xrefs = 0;
String idField = null;
// the column refering to 'localEntity'
String localIdField = null;
// the localEntiy
String localEntity = null;
// the column referring to 'remoteEntity'
String localEntityField = null;
// the column the localIdField is referning to
String remoteIdField = null;
// the column remoteEntity
String remoteEntity = null;
// the column the remoteIdField is referring to
String remoteEntityField = null;
for (Field f : e.getFields())
{
if (Field.Type.AUTOID.equals(f.getType()))
{
idField = f.getName();
}
else if (Field.Type.XREF_SINGLE.equals(f.getType()))
{
xrefs++;
if (xrefs == 1)
{
localIdField = f.getName();
// localEntityField is just the idField of
// the
// localEntity
localEntity = f.getXrefField().substring(0, f.getXrefField().indexOf("."));
localEntityField = f.getXrefField().substring(f.getXrefField().indexOf(".") + 1);
}
else
{
remoteIdField = f.getName();
// should be the id field of the remote
// entity
remoteEntity = f.getXrefField().substring(0, f.getXrefField().indexOf("."));
remoteEntityField = f.getXrefField().substring(f.getXrefField().indexOf(".") + 1);
}
}
}
// if valid mref, drop this entity and add mref fields
// to
// the other entities.
if (xrefs == 2 && (e.getFields().size() == 2 || idField != null))
{
// add mref on 'local' end
Entity localContainer = m.getEntity(localEntity);
Field localField = new Field();
if (localContainer.getField(e.getName()) == null)
{
localField.setName(e.getName());
}
localField.setType(Field.Type.XREF_MULTIPLE);
localField.setXrefField(remoteEntity + "." + remoteEntityField);
localField.setMrefName(e.getName());
localField.setMrefLocalid(localIdField);
localField.setMrefRemoteid(remoteIdField);
localContainer.getFields().add(localField);
// add mref to remote end
Entity remoteContainer = m.getEntity(remoteEntity);
Field remoteField = new Field();
remoteField.setType(Field.Type.XREF_MULTIPLE);
remoteField.setXrefField(localEntity + "." + localEntityField);
remoteField.setMrefName(e.getName());
// don't need to add local id as it is refering back
remoteField.setMrefLocalid(remoteIdField);
remoteField.setMrefRemoteid(localIdField);
if (remoteContainer.getField(e.getName()) == null)
{
remoteField.setName(e.getName());
}
else
{
throw new RuntimeException("MREF creation failed: there is already a field "
+ remoteContainer.getName() + "." + e.getName());
}
remoteContainer.getFields().add(remoteField);
// remove the link table as separate entity
toBeRemoved.add(e);
logger.debug("guessed mref " + e.getName());
}