package pt.ist.fenixframework.pstm.repository; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.lang.StringUtils; import org.apache.ojb.broker.PersistenceBrokerFactory; import org.apache.ojb.broker.metadata.ClassDescriptor; import org.apache.ojb.broker.metadata.CollectionDescriptor; import org.apache.ojb.broker.metadata.FieldDescriptor; import pt.ist.fenixframework.Config; import pt.ist.fenixframework.FenixFramework; import pt.ist.fenixframework.pstm.dml.FenixDomainModelWithOCC; import pt.ist.fenixframework.pstm.repository.database.DatabaseDescriptorFactory; import dml.DomainClass; import dml.DomainModel; import dml.Role; public class CheckOids { public static void main(String[] args) { Connection connection = null; try { final String dbAliasArg = getArg(args, 0); final String dbUserArg = getArg(args, 1); final String dbPassArg = getArg(args, 2); // all the remaining args are DML files final String[] domainModelFiles = Arrays.copyOfRange(args, 3, args.length); FenixFramework.bootStrap(new Config() {{ domainModelClass = FenixDomainModelWithOCC.class; domainModelPaths = domainModelFiles; dbAlias = dbAliasArg; dbUsername = dbUserArg; dbPassword = dbPassArg; }}); FenixFramework.initialize(); connection = PersistenceBrokerFactory.defaultPersistenceBroker().serviceConnectionManager().getConnection(); checkOids(connection); } catch (Exception ex) { ex.printStackTrace(); } finally { if (connection != null) { try { connection.close(); } catch (SQLException e) { // nothing can be done. } } } } private static List<String> getAllClassnames(DomainModel domainModel) { List<String> classnames = new ArrayList<String>(); for (DomainClass domClass : domainModel.getDomainClasses()) { classnames.add(domClass.getFullName()); } Collections.sort(classnames); return classnames; } public static void checkOids(Connection connection) throws Exception { checkOidsOfObjects(connection); checkOidsOfIndirectionTables(connection); } public static void checkOidsOfObjects(Connection connection) throws Exception { DomainModel domainModel = FenixFramework.getDomainModel(); List<String> classnames = getAllClassnames(domainModel); System.out.println("Total classes = " + classnames.size()); Map<String,ClassDescriptor> ojbMetadata = DatabaseDescriptorFactory.getDescriptorTable(); int num = 0; for (String classname : classnames) { ClassDescriptor cd = ojbMetadata.get(classname); if (cd == null) { System.err.println(" ##### Couldn't find a classDescriptor for class " + classname); } else { System.out.printf("%5d - ", num++); System.out.print("Checking oids for " + classname); checkOidsForClass(connection, domainModel.findClass(classname), cd); } } } private static void checkOidsForClass(Connection connection, DomainClass domClass, ClassDescriptor classDesc) throws Exception { String where = ""; // handle the special case of Fenix, where we are still using // the OJB_CONCRETE_CLASS column to identify the class of the objects if (classDesc.getFieldDescriptorByName("ojbConcreteClass") != null) { where = " where OJB_CONCRETE_CLASS = '" + domClass.getFullName() + "'"; } String tableName = classDesc.getFullTableName(); int numRows = countRows(connection, tableName, where); System.out.printf(" (table = %s, rows = %d)\n", tableName, numRows); StringBuilder selectStmt = new StringBuilder(); selectStmt.append("select ID_INTERNAL,OID"); List<String> foreignKeys = getForeignKeys(domClass, classDesc); // append all the KEYs and matching OIDs for (String fk : foreignKeys) { selectStmt.append(","); selectStmt.append(fk); selectStmt.append(",OID_"); selectStmt.append(fk.substring(4)); } selectStmt.append(" from "); selectStmt.append(tableName); selectStmt.append(where); // Now, execute the select and check the results Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(selectStmt.toString()); while (rs.next()) { int idInternal = rs.getInt(1); long oid = rs.getLong(2); if (! same(idInternal, oid)) { System.err.println(" !!! mismatch between ID_INTERNAL and OID: " + idInternal + " != " + oid); } // check all the foreign keys, also int pos = 3; for (String fk : foreignKeys) { int key = rs.getInt(pos++); long oidKey = rs.getLong(pos++); if (! same(key, oidKey)) { System.err.print(" ### mismatch between KEY and OID: " + key + " != " + oidKey); System.err.println(" (for colName = " + fk + " in object with OID = " + oid + ")"); } } } rs.close(); stmt.close(); } private static final class IndirectionTable implements Comparable<IndirectionTable> { private final String table; private final CollectionDescriptor colDesc; IndirectionTable(String table, CollectionDescriptor colDesc) { this.table = table; this.colDesc = colDesc; } public int compareTo(IndirectionTable other) { return this.table.compareTo(other.table); } public boolean equals(Object other) { return (other != null) && (other.getClass() == this.getClass()) && ((IndirectionTable)other).table.equals(this.table); } public int hashCode() { return table.hashCode(); } } public static void checkOidsOfIndirectionTables(Connection connection) throws Exception { Set<IndirectionTable> tablesToCheck = new TreeSet<IndirectionTable>(); for (ClassDescriptor classDesc : DatabaseDescriptorFactory.getDescriptorTable().values()) { for (CollectionDescriptor colDesc : (Iterable<CollectionDescriptor>)classDesc.getCollectionDescriptors()) { String tableName = colDesc.getIndirectionTable(); if (tableName != null) { tablesToCheck.add(new IndirectionTable(tableName, colDesc)); } } } System.out.println("Total indirection tables = " + tablesToCheck.size()); int num = 0; for (IndirectionTable indTable : tablesToCheck) { System.out.printf("%5d - ", num++); System.out.print("Checking oids for " + indTable.table); checkOidsForIndTable(connection, indTable.colDesc); } } public static void checkOidsForIndTable(Connection connection, CollectionDescriptor colDesc) throws Exception { String tableName = colDesc.getIndirectionTable(); int numRows = countRows(connection, tableName, ""); System.out.printf(" (rows = %d)\n", numRows); StringBuilder selectStmt = new StringBuilder(); selectStmt.append("select "); String firstKey = colDesc.getFksToThisClass()[0]; selectStmt.append(firstKey); selectStmt.append(","); selectStmt.append(firstKey.replace("KEY_", "OID_")); selectStmt.append(","); String secondKey = colDesc.getFksToItemClass()[0]; selectStmt.append(secondKey); selectStmt.append(","); selectStmt.append(secondKey.replace("KEY_", "OID_")); selectStmt.append(" from "); selectStmt.append(tableName); String[] foreignKeys = new String[] { firstKey, secondKey }; // Now, execute the select and check the results Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(selectStmt.toString()); while (rs.next()) { int pos = 1; for (String fk : foreignKeys) { int key = rs.getInt(pos++); long oidKey = rs.getLong(pos++); if (! same(key, oidKey)) { System.err.print(" ### mismatch between KEY and OID: " + key + " != " + oidKey); System.err.println(" (for colName = " + fk + ")"); } } } rs.close(); stmt.close(); } private static boolean same(int id, long oid) { return ((int)(oid & 0x7FFFFFFF)) == id; } private static int countRows(Connection connection, String tableName, String where) throws Exception { Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("select count(*) from " + tableName + where); rs.next(); int res = rs.getInt(1); rs.close(); stmt.close(); return res; } private static List<String> getForeignKeys(DomainClass domClass, ClassDescriptor classDesc) { List<String> fks = new ArrayList<String>(); while (domClass != null) { for (Role role : domClass.getRoleSlotsList()) { String roleName = role.getName(); if ((role.getMultiplicityUpper() == 1) && (roleName != null)) { String foreignKeyField = "key" + StringUtils.capitalize(roleName); FieldDescriptor fd = classDesc.getFieldDescriptorByName(foreignKeyField); fks.add(fd.getColumnName()); } } domClass = (DomainClass)domClass.getSuperclass(); } return fks; } private static String getArg(String[] args, int index) { if (args.length < index) { System.out.println("Usage: CheckOids <dbAlias> <dbUser> <dbPasswd> <dmlFile>+"); System.exit(1); } return args[index]; } }