package fitnesse.testsystems.slim.tables; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import fitnesse.testsystems.slim.SlimTestContext; import fitnesse.testsystems.slim.Table; public class SlimTableFactory { private static final Logger LOG = Logger.getLogger(SlimTableFactory.class.getName()); private static final Map<Class<? extends SlimTable>, Constructor<? extends SlimTable>> CONSTRUCTOR_MAP = new HashMap<>(); private final Map<String, Class<? extends SlimTable>> tableTypes; private final Map<String, String> tableTypeArrays; private final Map<String, String> aliasArrays; public SlimTableFactory() { tableTypes = new HashMap<>(16); tableTypeArrays = new HashMap<>(); aliasArrays = new HashMap<>(); addTableType("dt", DecisionTable.class); addTableType("decision", DecisionTable.class); addTableType("ddt", DynamicDecisionTable.class); addTableType("dynamic decision", DynamicDecisionTable.class); addTableType("ordered query", OrderedQueryTable.class); addTableType("subset query", SubsetQueryTable.class); addTableType("query", QueryTable.class); addTableType("table", TableTable.class); addTableType("script", ScriptTable.class); addTableType("script:", ScriptTable.class); addTableType("scenario", ScenarioTable.class); addTableType("import", ImportTable.class); addTableType("library", LibraryTable.class); addTableType("baseline", BaselineDecisionTable.class); } protected SlimTableFactory(Map<String, Class<? extends SlimTable>> tableTypes, Map<String, String> tableTypeArrays, Map<String, String> aliasArrays) { this.tableTypes = tableTypes; this.tableTypeArrays = tableTypeArrays; this.aliasArrays = aliasArrays; } public void addTableType(String nameOrPrefix, Class<? extends SlimTable> tableClass) { if (tableTypes.get(nameOrPrefix) != null) { throw new IllegalStateException("A table type named '" + nameOrPrefix + "' already exists"); } tableTypes.put(nameOrPrefix.toLowerCase().replaceAll(":", ""), tableClass); } public SlimTable makeSlimTable(Table table, String tableId, SlimTestContext slimTestContext) { SlimTable newTable; String tableType = getFullTableName(table.getCellContents(0, 0)); //table.substitute(0, 0, tableType); // First the "exceptions to the rule" if ( tableType.equalsIgnoreCase("define alias")) { parseDefineAliasTable(table); return null; } else if (tableType.equalsIgnoreCase("define table type")) { parseDefineTableTypeTable(table); return null; } else if (tableType.equalsIgnoreCase("comment") || tableType.startsWith("comment:")) { return null; } Class<? extends SlimTable> tableClass = getTableType(tableType); if (tableClass != null) { newTable = newTableForType(tableClass, table, tableId, slimTestContext); } else if (!hasColon(tableType)) { newTable = new DecisionTable(table, tableId, slimTestContext); }else { newTable = new SlimErrorTable(table, tableId, slimTestContext); } newTable.setFixtureName(getRawFixtureName(tableType)); newTable.setTearDown(table.isTearDown()); return newTable; } private boolean hasColon(String tableType) { return tableType.contains(":"); } public String getRawTableTypeName(String fullTableName) { if (hasColon(fullTableName)) { return fullTableName.substring(0, fullTableName.indexOf(':')).trim().toLowerCase(); } return ""; } public String getRawFixtureName(String fullTableName) { if (hasColon(fullTableName)) { return fullTableName.substring(fullTableName.indexOf(':') + 1).trim(); } return fullTableName; } public Class<? extends SlimTable> getTableType(String tableType) { if (hasColon(tableType)) { tableType = tableType.substring(0, tableType.indexOf(':')); } return tableTypes.get(tableType.toLowerCase().trim()); } private SlimTable newTableForType(Class<? extends SlimTable> tableClass, Table table, String tableId, SlimTestContext slimTestContext) { try { return createTable(tableClass, table, tableId, slimTestContext); } catch (TableCreationException e) { LOG.log(Level.WARNING, e.getMessage(), e); return new SlimErrorTable(table, tableId, slimTestContext); } } public static <T extends SlimTable> T createTable(Class<T> tableClass, Table table, String tableId, SlimTestContext slimTestContext) throws TableCreationException { Constructor<? extends SlimTable> constructor = CONSTRUCTOR_MAP.get(tableClass); try { if (constructor == null) { constructor = tableClass.getConstructor(Table.class, String.class, SlimTestContext.class); CONSTRUCTOR_MAP.put(tableClass, constructor); } return (T) constructor.newInstance(table, tableId, slimTestContext); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new TableCreationException("Can not create new table instance for class " + tableClass.getName(), e); } } private String getFullTableName(String tableName) { String disgracedName = Disgracer.disgraceClassName(getRawFixtureName(tableName)); //check for an alias definition if (aliasArrays.containsKey(disgracedName)) { String fixtureName = aliasArrays.get(disgracedName); String tableType = getRawTableTypeName(tableName); if (hasColon(fixtureName)){ tableType = getRawTableTypeName(fixtureName); fixtureName = getRawFixtureName(fixtureName); if (tableType.isEmpty()) tableType = getRawTableTypeName(tableName); if (fixtureName.isEmpty()) fixtureName = getRawFixtureName(tableName); } return tableType + ":" + fixtureName; }else if (hasColon(tableName)) { // a table type definition exits in the table return tableName; } //check for a table type defined in a table type definition else if (tableTypeArrays.containsKey(disgracedName)) { return tableTypeArrays.get(disgracedName) + ":" + tableName; } return tableName; } private SlimTable parseDefineTableTypeTable(Table table) { for (int rowIndex = 1; rowIndex < table.getRowCount(); rowIndex++) parseDefineTableTypeRow(table, rowIndex); return null; } private void parseDefineTableTypeRow(Table table, int rowIndex) { if (table.getColumnCountInRow(rowIndex) >= 2) { String fixtureName = table.getCellContents(0, rowIndex); String fixture = Disgracer.disgraceClassName(fixtureName); String tableSpecifier = table.getCellContents(1, rowIndex).toLowerCase(); tableTypeArrays.put(fixture, makeTableType(tableSpecifier)); } } public void addDefaultTableType(String fixture, String tableType) { tableTypeArrays.put(fixture, tableType); } public void addAlias(String alias, String fixture) { String disgracedAlias = Disgracer.disgraceClassName(alias); aliasArrays.put(disgracedAlias, fixture); } private String makeTableType(String tableSpecifier) { tableSpecifier = tableSpecifier.replace(':', ' '); if (tableSpecifier.startsWith("as")) tableSpecifier = tableSpecifier.substring(2); return tableSpecifier.trim(); } private SlimTable parseDefineAliasTable(Table table) { for (int rowIndex = 1; rowIndex < table.getRowCount(); rowIndex++) parseDefineAliasRow(table, rowIndex); return null; } private void parseDefineAliasRow(Table table, int rowIndex) { if (table.getColumnCountInRow(rowIndex) >= 2) { String fixtureName = table.getCellContents(0, rowIndex); String tableSpecifier = table.getCellContents(1, rowIndex).trim(); addAlias(fixtureName, tableSpecifier); } } public SlimTableFactory copy() { return new SlimTableFactory(new HashMap<>(tableTypes), new HashMap<>(tableTypeArrays), new HashMap<>(aliasArrays)); } }