public EntityMetaDataUtils() { DefaultEntityMetaData characteristic = new DefaultEntityMetaData("Characteristic"); characteristic.addAttribute("identifier"); omxEntities.put(characteristic.getName(), characteristic); // TODO: categroy should be converted DefaultEntityMetaData category = new DefaultEntityMetaData("Category"); category.addAttribute("identifier"); omxEntities.put(category.getName(), category); }
public Collection<EntityMetaData> extractMetaData(DataSource ds) throws ClassNotFoundException { Map<String, DefaultEntityMetaData> result = new LinkedHashMap<String, DefaultEntityMetaData>(); Connection conn = null; try { conn = ds.getConnection(); DatabaseMetaData md = conn.getMetaData(); ResultSet tableInfo = md.getTables(null, null, "%", new String[] {"TABLE"}); // first add all entities while (tableInfo.next()) { DefaultEntityMetaData entity = new DefaultEntityMetaData(tableInfo.getString("TABLE_NAME")); result.put(entity.getName(), entity); } // again, then add columns tableInfo = md.getTables(null, null, "%", new String[] {"TABLE"}); while (tableInfo.next()) { DefaultEntityMetaData entity = result.get(tableInfo.getString("TABLE_NAME")); // ADD THE COLUMNS ResultSet fieldInfo = md.getColumns(null, null, tableInfo.getString("TABLE_NAME"), null); while (fieldInfo.next()) { DefaultAttributeMetaData f = new DefaultAttributeMetaData(fieldInfo.getString("COLUMN_NAME")); // FIXME refactor out f.setDataType( MolgenisFieldTypes.getType( org.molgenis.model.jaxb.Field.Type.getType(fieldInfo.getInt("DATA_TYPE")) .toString())); f.setDefaultValue(fieldInfo.getString("COLUMN_DEF")); entity.addAttributeMetaData(f); if (md.getDatabaseProductName().toLowerCase().contains("mysql")) { // accomodate mysql CURRENT_TIMESTAMP if ("CURRENT_TIMESTAMP".equals(f.getDefaultValue()) && (f.getDataType().equals(MolgenisFieldTypes.DATETIME) || f.getDataType().equals(MolgenisFieldTypes.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.getDataType().equals(MolgenisFieldTypes.INT) && fieldInfo.getObject("IS_AUTOINCREMENT") != null) { f.setAuto(fieldInfo.getBoolean("IS_AUTOINCREMENT")); } if (f.getDataType().equals(MolgenisFieldTypes.STRING)) { if (fieldInfo.getInt("COLUMN_SIZE") > 255) { f.setDataType(MolgenisFieldTypes.TEXT); // f.setLength(fieldInfo.getInt("COLUMN_SIZE")); } else { // if (fieldInfo.getInt("COLUMN_SIZE") != 255) // {f.setLength(fieldInfo.getInt("COLUMN_SIZE"));} f.setDataType(null); // defaults to string } } // xrefs ResultSet xrefInfo = md.getImportedKeys(null, null, tableInfo.getString("TABLE_NAME")); while (xrefInfo.next()) { if (xrefInfo.getString("FKCOLUMN_NAME").equals(fieldInfo.getString("COLUMN_NAME"))) { f.setDataType(MolgenisFieldTypes.XREF); // problem: PKTABLE_NAME is lowercase, need to be // corrected later? f.setRefEntity(result.get(xrefInfo.getString("PKTABLE_NAME"))); // + "." // + xrefInfo.getString("PKCOLUMN_NAME")); } } } // // 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(null, 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) { ((DefaultAttributeMetaData) entity.getAttribute(index.get(0))).setUnique(true); } else { // TODO: composite keys! // 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 (DefaultEntityMetaData e : result.values()) { List<AttributeMetaData> toBeRemoved = new ArrayList<AttributeMetaData>(); for (AttributeMetaData f : e.getAttributes()) { if (MolgenisFieldTypes.XREF.equals(f.getDataType()) && Boolean.TRUE.equals(f.isUnique())) { e.setExtends(f.getRefEntity()); toBeRemoved.add(f); } } // for (DefaultEntityMetaData f : toBeRemoved) // { // //e.removeAttributeMetaData(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()); // } // } // } // m.getEntities().removeAll(toBeRemoved); // // // logger.info(MolgenisLanguage.summarize(m)); // logger.info(toString(m)); // return m; logger.debug(entity); } } catch (Exception ex) { logger.error(ex); ex.printStackTrace(); return null; } finally { try { conn.close(); } catch (Exception ex2) { throw new RuntimeException(ex2); } } return null; }