package pickMaint; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; /** * AS400Interface * * @TODO Implement production/test data selection from log-in prompt * * This class is designed to abstract the database transactions required by the GUI components in Editor.java. * * A connection is established with the AS400 upon instantiating this class. * There is only one constructor which takes two strings (User and Password). * * All multiple use SQL statements are pre-compiled into java.sql.PreparedStatement objects during initialization. * * The following are cached locally (into HashMaps) from the server during init: * Down time reason codes/descriptions * Weaver numbers/names * Loom speeds (in 1000s of picks/hour) * These items are used frequently for calculation/display purposes and don't often change so it is more than enough to * cache them temporarily during application startup. * * @author Wesley Ray */ public class AS400Interface { private String LIB = "STMDATA"; private static final Logger LOGGER = Logger.getLogger(AS400Interface.class.getName()); private static final HashMap downTimeCodeLookup = new HashMap(); private static final HashMap weaverNameLookup = new HashMap(); private static final HashMap loomPPHLookup = new HashMap(); private Connection conn; //java.sql.Connection object private PreparedStatement queryLoomds; private PreparedStatement queryLoomds2; private PreparedStatement adjPicksLoomds; private PreparedStatement adjPicksLoomds2; private PreparedStatement chgWeaverLoomds; private PreparedStatement chgWeaverLoomds2; private PreparedStatement chgDtCodeLoomds; private PreparedStatement chgDtCodeLoomds2; private PreparedStatement adjHoursLoomds; private PreparedStatement adjHoursLoomds2; private PreparedStatement adjHrsPksLoomds; private PreparedStatement adjHrsPksLoomds2; private PreparedStatement newLoomDSRecord; private PreparedStatement newLoomDS2Record; private PreparedStatement delLoomDSRecord; private PreparedStatement delLoomDS2Record; private PreparedStatement getProdLoomHours; private PreparedStatement getProdPicks; private PreparedStatement getNobLoomHours; private PreparedStatement getNobPicks; private PreparedStatement getSampLoomHours; private PreparedStatement getSampPicks; private PreparedStatement getShiftLength; private PreparedStatement getEfficiencies; public AS400Interface(String usr, String psw, boolean production) throws SQLException{ this.LIB = production ? "STMDATA" : "WES"; //Sets name of library to be compiled into SQL statements //Register AS400 DB2 driver and open a connection with the AS400 LOGGER.info("Connecting to AS400 as user: " + usr); DriverManager.registerDriver(new com.ibm.as400.access.AS400JDBCDriver()); this.conn = DriverManager.getConnection("jdbc:as400://0.0.0.0", usr, psw); setUpDTcodeHashMap(); //Grabs down time codes from server setUpWeaverHashMap(); //Grabs weaver names from server setUpLoomPPHHashMap(); //Grabs loom speeds from server preCompileStatements(); //Pre-compile SQL statements } /** * Called by the constructor to pre-compile all of the SQl statements used by the program. * @throws SQLException - Shouldn't happen, usually only thrown when there are syntax errors in the queries. */ private final void preCompileStatements() throws SQLException{ LOGGER.info("Pre-compiling multiple use SQL statements."); queryLoomds = this.conn.prepareStatement("SELECT lddate, " + " ldloom, " + " ldshif, " + " ldweav, " + " wvrnam, " + " ldsty1, " + " ldhrs, " + " ldpick, " + " lmppm, " + " lmppms, " + " ( ( 100.0 * lmppm ) / 82.0 ) AS picksHR, " + " ( ( 100.0 * lmppms ) / 82.0 ) AS picksHRsam, " + " ldreas, " + " ldcut1, " + " ldcut2, " + " bmtycd, " + " lddlcd " + "FROM " + LIB + ".loomds, " + " stmdata.iewvms, " + " stmdata.loomms " + "WHERE ldweav = wvr# " + " AND ldloom = lmlomn " + " AND LDDATE = ? " + " AND LDSHIF = ? " + "ORDER BY ldloom"); queryLoomds2 = this.conn.prepareStatement("SELECT ldpick, " + " ldhrs " + "FROM " + LIB + ".loomds2 " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + "ORDER BY ldloom"); adjPicksLoomds = this.conn.prepareStatement("UPDATE " + LIB + ".loomds " + "SET ldpick = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); adjPicksLoomds2 = this.conn.prepareStatement("UPDATE " + LIB + ".loomds2 " + "SET ldpick = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); chgWeaverLoomds = this.conn.prepareStatement("UPDATE " + LIB + ".loomds " + "SET ldweav = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); chgWeaverLoomds2 = this.conn.prepareStatement("UPDATE " + LIB + ".loomds2 " + "SET ldweav = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); chgDtCodeLoomds = this.conn.prepareStatement("UPDATE " + LIB + ".loomds " + "SET ldreas = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); chgDtCodeLoomds2 = this.conn.prepareStatement("UPDATE " + LIB + ".loomds2 " + "SET ldreas = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); adjHoursLoomds = this.conn.prepareStatement("UPDATE " + LIB + ".loomds " + "SET ldhrs = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); adjHoursLoomds2 = this.conn.prepareStatement("UPDATE " + LIB + ".loomds2 " + "SET ldhrs = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); adjHrsPksLoomds = this.conn.prepareStatement("UPDATE " + LIB + ".loomds " + "SET ldhrs = ?, " + " ldpick = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); adjHrsPksLoomds2 = this.conn.prepareStatement("UPDATE " + LIB + ".loomds2 " + "SET ldhrs = ?, " + " ldpick = ? " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = ? "); newLoomDSRecord = this.conn.prepareStatement("insert into " + LIB + ".LOOMDS values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); newLoomDS2Record = this.conn.prepareStatement("insert into " + LIB + ".LOOMDS2 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); delLoomDSRecord = this.conn.prepareStatement("DELETE FROM " + LIB + ".loomds " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = 0 "); delLoomDS2Record = this.conn.prepareStatement("DELETE FROM " + LIB + ".loomds2 " + "WHERE lddate = ? " + " AND ldloom = ? " + " AND ldshif = ? " + " AND ldweav = ? " + " AND ldsty1 = ? " + " AND ldsty2 = 0 "); getProdLoomHours = this.conn.prepareStatement("SELECT Sum(ldhrs) AS loom_hours " + "FROM " + LIB + ".loomds " + "WHERE lddate = ? " + " AND ldshif = ? " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getProdPicks = this.conn.prepareStatement("SELECT Sum(ldpick) AS total_picks " + "FROM " + LIB + ".loomds " + "WHERE lddate = ? " + " AND ldshif = ? " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getNobLoomHours = this.conn.prepareStatement("SELECT Sum(ldhrs) AS loom_hours " + "FROM " + LIB + ".loomds2 " + "WHERE lddate = ? " + " AND ldshif = ? " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getNobPicks = this.conn.prepareStatement("SELECT Sum(ldpick) AS total_picks " + "FROM " + LIB + ".loomds2 " + "WHERE lddate = ? " + " AND ldshif = ? " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getSampLoomHours = this.conn.prepareStatement("SELECT Sum(ldhrs) AS total_hours " + "FROM " + LIB + ".loomds " + "WHERE lddate = ? " + " AND ldshif = ? " + " AND ldsty1 = ' SAM' " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getSampPicks = this.conn.prepareStatement("SELECT Sum(ldpick) AS total_picks " + "FROM " + LIB + ".loomds " + "WHERE lddate = ? " + " AND ldshif = ? " + " AND ldsty1 = ' SAM' " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getShiftLength = this.conn.prepareStatement("SELECT Max(ldhrs) AS shift_length " + "FROM " + LIB + ".loomds " + "WHERE lddate = ? " + " AND ldshif = ? " + "GROUP BY lddate, " + " ldshif " + "ORDER BY lddate "); getEfficiencies = this.conn.prepareStatement("SELECT ( ( 100.0 / 82.0 ) * lmppm ) AS target_pph, " + " ( ldpick / ldhrs ) AS acutal_pph " + "FROM " + LIB + ".loomds " + " INNER JOIN stmdata.loomms " + " ON ldloom = lmlomn " + "WHERE lddate = ? " + " AND ldshif = ? " + " AND ldhrs > 0 "); } /** * Quietly close and null ALL PreparedStatement objects and the java.sql.Connection object. * * If an exception is raised while closing one of the PreparedStatement objects the Connection object * will be closed in the finally block. */ public void close(){ try { queryLoomds.close(); queryLoomds2.close(); adjPicksLoomds.close(); adjPicksLoomds2.close(); chgWeaverLoomds.close(); chgWeaverLoomds2.close(); chgDtCodeLoomds.close(); chgDtCodeLoomds2.close(); adjHoursLoomds.close(); adjHoursLoomds2.close(); adjHrsPksLoomds.close(); adjHrsPksLoomds2.close(); newLoomDSRecord.close(); newLoomDS2Record.close(); delLoomDSRecord.close(); delLoomDS2Record.close(); getProdLoomHours.close(); getProdPicks.close(); getNobLoomHours.close(); getNobPicks.close(); getSampLoomHours.close(); getSampPicks.close(); getShiftLength.close(); getEfficiencies.close(); conn.close(); queryLoomds = null; queryLoomds2 = null; adjPicksLoomds = null; adjPicksLoomds2 = null; chgWeaverLoomds = null; chgWeaverLoomds2 = null; chgDtCodeLoomds = null; chgDtCodeLoomds2 = null; adjHoursLoomds = null; adjHoursLoomds2 = null; adjHrsPksLoomds = null; adjHrsPksLoomds2 = null; newLoomDSRecord = null; newLoomDS2Record = null; delLoomDSRecord = null; delLoomDS2Record = null; getProdLoomHours = null; getProdPicks = null; getNobLoomHours = null; getNobPicks = null; getSampLoomHours = null; getSampPicks = null; getShiftLength = null; getEfficiencies = null; conn = null; LOGGER.info("Open connection resources closed successfully!"); } catch(SQLException e){ } finally { if(conn != null) try { conn.close(); conn = null; } catch (SQLException e) { } } } /** * Queries the AS400 for picks records for the given date/shift combination. Returns results as a LoomDSRecord[] * @param date - Date to use in query * @param shift - Shift to use in query * @return Pick records for date/shift as LoomDSRecord[] * @throws SQLException */ public LoomDSRecord[] getShiftDetail(int date, int shift) throws SQLException{ LOGGER.info("Fetching picks for " + ((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "") + " shift on " + new SimpleDateFormat("MM/dd/yyyy").format(intToDate(date)) + " from server."); ArrayList list = new ArrayList(); queryLoomds.setInt(1, date); queryLoomds.setInt(2, shift); ResultSet rs = queryLoomds.executeQuery(); while(rs.next()){ list.add(new LoomDSRecord(this, rs)); } rs.close(); if(list.size() < 1) throw new SQLException("Empty result set for " + ((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "" + shift) + " Shift on " + intToDate(date)); return list.toArray(new LoomDSRecord[list.size()]); //Return a fixed length array rather than an ArrayList, we are done adding elements } /** * The actual hours and picks for no bonus looms reside in LOOMDS2. If the LoomDSRecord constructor detects that a record is no bonus * it will call this method to query LOOMDS2 for the hours and picks for that record. * @param date - date to use in query * @param loom - loom # to use in query * @param shift - Shift to use in query * @param weaver - weaver # to use in query * @return - float[] return[0] contains the hours, float[1] contains the picks * @throws SQLException */ public float[] getLoomDS2HoursPicks(int date, int loom, int shift, int weaver) throws SQLException{ queryLoomds2.setInt(1, date); queryLoomds2.setInt(2, loom); queryLoomds2.setInt(3, shift); queryLoomds2.setInt(4, weaver); ResultSet rs = queryLoomds2.executeQuery(); if(rs.next()) { return new float[]{rs.getFloat(2) , (float) rs.getInt(1)}; } else { LOGGER.severe("No record found in LOOMDS2 for " + weaverLookup(weaver) + " (" + weaver + ") on loom " + loom + " for " + ((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "") + " shift on " + new SimpleDateFormat("MM/dd/yyyy").format(intToDate(date))); return new float[]{-1, -1}; } } /** * Returns the length of the given shift on the given date. * This works by returning the largest value found for the HOURS column within the records selected based on the * date and shift supplied. * * SELECT Max(ldhrs) AS shift_length * FROM stmdata.loomds " * WHERE lddate = ? * AND ldshif = ? * GROUP BY lddate, * ldshif * ORDER BY lddate * * @param date - The date of the shift you want the length of * @param shift - The shift you want the length of * @return The length of the shift in hours * @throws SQLException */ public float getShiftLength(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getShiftLength.setInt(1, d); getShiftLength.setInt(2, shift); ResultSet rs = getShiftLength.executeQuery(); if(rs.next()) return rs.getFloat(1); else throw new SQLException("Got an empty result set for shift length query. Your guess is as good as mine..."); } /** * Returns the shift's efficiency as a function of (TOTAL_PICKS / PICKS_POSSIBLE) * * This query is run: * * SELECT ( ( 100.0 / 82.0 ) * lmppm ) AS target_pph, * ( ldpick / ldhrs ) AS acutal_pph * FROM stmdata.loomds * INNER JOIN stmdata.loomms * ON ldloom = lmlomn * WHERE lddate = ? * AND ldshif = ? * AND ldhrs > 0 * * The result set is looped over; summing up target and actual picks per hour for the entire shift. * * @param date - The date of the shift you want * @param shift - The shift you want * @return (TOTAL_PICKS / PICKS_POSSIBLE) for the entire shift. * @throws SQLException */ public float getShiftEfficiency(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getEfficiencies.setInt(1, d); getEfficiencies.setInt(2, shift); ResultSet rs = getEfficiencies.executeQuery(); double target = 0; double actual = 0; while(rs.next()){ target += rs.getDouble(1); actual += rs.getDouble(2); } return (float) (actual / target); } /** * Totals and returns loom-hours for bonus looms only. For the given date and shift. * * SELECT Sum(ldhrs) AS loom_hours * FROM stmdata.loomds * WHERE lddate = ? * AND ldshif = ? * GROUP BY lddate, * ldshif * ORDER BY lddate * * @param date - The date of the shift you want * @param shift - The shift you want * @return Total production loom hours for the supplied shift * @throws SQLException */ public float getProductionLoomHours(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getProdLoomHours.setInt(1, d); getProdLoomHours.setInt(2, shift); ResultSet rs = getProdLoomHours.executeQuery(); if(rs.next()) return rs.getFloat(1); else throw new SQLException("Got an empty result set for aggregate production hours query. Your guess is as good as mine..."); } /** * Totals and returns all bonus picks for the given shift. * * SELECT Sum(ldpick) AS total_picks * FROM stmdata.loomds * WHERE lddate = ? * AND ldshif = ? * GROUP BY lddate, * ldshif * ORDER BY lddate * * @param date - The date of the shift you want * @param shift - The shift you want * @return Total production picks for the supplied shift * @throws SQLException */ public int getProductionPicks(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getProdPicks.setInt(1, d); getProdPicks.setInt(2, shift); ResultSet rs = getProdPicks.executeQuery(); if(rs.next()) return rs.getInt(1); else throw new SQLException("Got an empty result set for aggregate production picks query. Your guess is as good as mine..."); } /** * Totals and returns no-bonus loom-hours for the supplied shift. * * SELECT Sum(ldhrs) AS loom_hours * FROM stmdata.loomds2 * WHERE lddate = ? * AND ldshif = ? * GROUP BY lddate, * ldshif * ORDER BY lddate * * @param date - The date of the shift you want * @param shift - The shift you want * @return Total no-bonus loom-hours for the supplied shift * @throws SQLException */ public float getNoBonusLoomHours(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getNobLoomHours.setInt(1, d); getNobLoomHours.setInt(2, shift); ResultSet rs = getNobLoomHours.executeQuery(); if(rs.next()) return rs.getFloat(1); else throw new SQLException("Got an empty result set for aggregate no bonus hours query. Your guess is as good as mine..."); } /** * Totals and returns all no-bonus picks for the supplied shift. * * SELECT Sum(ldpick) AS total_picks * FROM stmdata.loomds2 * WHERE lddate = ? * AND ldshif = ? * GROUP BY lddate, * ldshif * ORDER BY lddate * * @param date - The date of the shift you want * @param shift - The shift you want * @return Total no-bonus picks for the supplied shift * @throws SQLException */ public int getNoBonusPicks(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getNobPicks.setInt(1, d); getNobPicks.setInt(2, shift); ResultSet rs = getNobPicks.executeQuery(); if(rs.next()) return rs.getInt(1); else throw new SQLException("Got an empty result set for aggregate no bonus picks query. Your guess is as good as mine..."); } /** * Totals and returns all loom-hours that can be attributed to sample cuts for the supplied shift. * * SELECT Sum(ldhrs) AS total_hours * FROM stmdata.loomds * WHERE lddate = ? * AND ldshif = ? * AND ldsty1 = ' SAM' * GROUP BY lddate, * ldshif * ORDER BY lddate * * * @param date - The date of the shift you want * @param shift - The shift you want * @return total loom-hours that ran samples for the shift * @throws SQLException */ public float getSampleLoomHours(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getSampLoomHours.setInt(1, d); getSampLoomHours.setInt(2, shift); ResultSet rs = getSampLoomHours.executeQuery(); if(rs.next()) return rs.getFloat(1); else throw new SQLException("Got an empty result set for aggregate no bonus hours query. Your guess is as good as mine..."); } /** * Totals and returns the amount of sample picks woven for the supplied shift * * SELECT Sum(ldpick) AS total_picks * FROM stmdata.loomds * WHERE lddate = ? * AND ldshif = ? * AND ldsty1 = ' SAM' * GROUP BY lddate, * ldshif * ORDER BY lddate * * @param date - The date of the shift you want * @param shift - The shift you want * @return total sample picks woven during the supplied shift * @throws SQLException */ public int getSamplePicks(Date date, int shift) throws SQLException{ int d = AS400Interface.dateToInt(date); getSampPicks.setInt(1, d); getSampPicks.setInt(2, shift); ResultSet rs = getSampPicks.executeQuery(); if(rs.next()) return rs.getInt(1); else throw new SQLException("Got an empty result set for aggregate no bonus picks query. Your guess is as good as mine..."); } /** * Deletes the record from the database represented by the information contained in the supplied LoomDSRecord object. * Specifically, it uses the date, loom #, shift, weaver #, and style from the LoomDSRecord object for the where criteria * in the delete statement. * @param record - The record to be removed from the database * @throws SQLException */ public void delRecord(LoomDSRecord record) throws SQLException{ delLoomDSRecord.setInt(1, dateToInt(record.getDate())); delLoomDSRecord.setInt(2, record.getLoomNumber()); delLoomDSRecord.setInt(3, record.getShift()); delLoomDSRecord.setInt(4, record.getWeaverNumber()); delLoomDSRecord.setString(5, " " + record.getLdStyle().trim()); LOGGER.info(delLoomDSRecord.executeUpdate() + " row deleted in LOOMDS"); if(!record.isBonus()){ delLoomDS2Record.setInt(1, dateToInt(record.getDate())); delLoomDS2Record.setInt(2, record.getLoomNumber()); delLoomDS2Record.setInt(3, record.getShift()); delLoomDS2Record.setInt(4, record.getWeaverNumber()); delLoomDS2Record.setString(5, " " + record.getLdStyle().trim()); LOGGER.info(delLoomDS2Record.executeUpdate() + " row deleted in LOOMDS2"); } } /** * Creates a new entry in the database. If the entry is to be "no bonus" a record must also be written into LOOMDS2. * The actual hours and picks for no bonus entries are stored in LOOMDS2 and LOOMDS gets zeros instead. For normal entries * a single record is written into LOOMDS. * * @param date - Date. * @param loom - Loom Number. * @param shift - Shift. * @param weaver - Weaver # that worked. * @param style1 - BLN, TRL, or SAM. Only required if noBonus. * @param hours - How many hours worked. * @param picks - How many picks woven. * @param dtCode - Down time reason code, if there is one. * @param cut - The cut number. For sample cuts only. * @param cutSuffix - The character portion of the cut number, if there is one. For sample cuts only. * @param typeCode - [B]lanket, [I]nitial, or [T]rial. Only required if noBonus. I is never used. * @param noBonus - Did this loom run production for bonus or not? * @throws SQLException */ public void addRecord(Date date, int loom, int shift, int weaver, String style1, Double hours, int picks, String dtCode, int cut, String cutSuffix, String typeCode, boolean noBonus) throws SQLException { newLoomDSRecord.setObject(1, dateToInt(date)); //Date YYMMDD newLoomDSRecord.setObject(2, loom); //Loom # newLoomDSRecord.setObject(3, shift); //Shift newLoomDSRecord.setObject(4, weaver); //Weaver # newLoomDSRecord.setObject(5, style1); //Style 1 ϵ [BLN, TRL, SAM] newLoomDSRecord.setObject(6, 0); //Style 2 - I've never seen this anything other than zero newLoomDSRecord.setObject(7, (noBonus ? 0 : hours)); //Hours newLoomDSRecord.setObject(8, (noBonus ? 0 : picks)); //Picks newLoomDSRecord.setObject(9, dtCode); //Down time Reason Code newLoomDSRecord.setObject(10, "D"); //Loom Type - Always "D" for Dornier newLoomDSRecord.setObject(11, 0); //Loom Fixer - Never seems to be filled in newLoomDSRecord.setInt(12, cut); //Cut 1 - For when samples are cut in on production looms newLoomDSRecord.setObject(13, cutSuffix); //Cut 2 - For when samples are cut in on production looms newLoomDSRecord.setObject(14, typeCode); //Type code ϵ [B, I, T] newLoomDSRecord.setObject(15, " "); //Filler newLoomDSRecord.setObject(16, (noBonus ? "N" : " ")); //Delete Code - In LOOMDS if it is no bonus picks write an "N" LOGGER.info(newLoomDSRecord.executeUpdate() + " row added to LOOMDS"); if(noBonus){ newLoomDS2Record.setObject(1, dateToInt(date)); //Date YYMMDD newLoomDS2Record.setObject(2, loom); //Loom # newLoomDS2Record.setObject(3, shift); //Shift newLoomDS2Record.setObject(4, weaver); //Weaver # newLoomDS2Record.setObject(5, style1); //Style 1 ϵ [BLN, TRL, SAM] newLoomDS2Record.setObject(6, 0); //Style 2 - I've never seen this anything other than zero newLoomDS2Record.setObject(7, hours); //Hours newLoomDS2Record.setObject(8, picks); //Picks newLoomDS2Record.setObject(9, dtCode); //Down time Reason Code newLoomDS2Record.setObject(10, "D"); //Loom Type - Always "D" for Dornier newLoomDS2Record.setObject(11, 0); //Loom Fixer - Never seems to be filled in newLoomDS2Record.setInt(12, cut); //Cut 1 - For when samples are cut in on production looms newLoomDS2Record.setObject(13, cutSuffix); //Cut 2 - For when samples are cut in on production looms newLoomDS2Record.setObject(14, typeCode); //Type code ϵ [B, I, T] newLoomDS2Record.setObject(15, " "); //Filler newLoomDS2Record.setObject(16, " "); //Delete Code LOGGER.info(newLoomDS2Record.executeUpdate() + " row added to LOOMDS2"); } } /** * "Sample Cuts" are records with particular values for a few of the fields to indicate that they * are indeed samples that were cut into the production schedule for that loom. * * Parameter 5 will always be: " SAM" * Parameter 9 will always be: " " * Parameter 14 will always be: "T" * * Additionally a cut number is required for sample cuts * * @param source * @param cut * @param cutSuffix * @param hours * @param picks * @throws SQLException */ public void addSampleCut(LoomDSRecord source, int cut, String cutSuffix, Double hours, int picks) throws SQLException{ newLoomDSRecord.setObject(1, dateToInt(source.getDate())); //Date YYMMDD newLoomDSRecord.setObject(2, source.getLoomNumber()); //Loom # newLoomDSRecord.setObject(3, source.getShift()); //Shift newLoomDSRecord.setObject(4, source.getWeaverNumber()); //Weaver # newLoomDSRecord.setObject(5, " SAM"); //Style 1 ϵ [BLN, TRL, SAM] newLoomDSRecord.setObject(6, 0); //Style 2 - I've never seen this anything other than zero newLoomDSRecord.setObject(7, hours); //Hours newLoomDSRecord.setObject(8, picks); //Picks newLoomDSRecord.setObject(9, " "); //Down time Reason Code newLoomDSRecord.setObject(10, "D"); //Loom Type - Always "D" for Dornier newLoomDSRecord.setObject(11, 0); //Loom Fixer - Never seems to be filled in newLoomDSRecord.setInt(12, cut); //Cut 1 - For when samples are cut in on production looms newLoomDSRecord.setObject(13, cutSuffix); //Cut 2 - For when samples are cut in on production looms newLoomDSRecord.setObject(14, "T"); //Type code ϵ [B, I, T] newLoomDSRecord.setObject(15, " "); //Filler newLoomDSRecord.setObject(16, " "); //Delete Code - In LOOMDS if it is no bonus picks write an "N" LOGGER.info(newLoomDSRecord.executeUpdate() + " row added to LOOMDS"); } /** * Adjusts hours and picks in a single transaction. * See adjustHours() and adjustPicks() for detailed information. * * @param record - A LoomDSRecord representative of the record you wish to change on the server * @throws SQLException */ public void adjustHoursPicks(LoomDSRecord record) throws SQLException{ if(record.isBonus()){ adjHrsPksLoomds.setObject(1, record.getHours()); adjHrsPksLoomds.setObject(2, record.getPicks()); adjHrsPksLoomds.setInt(3, dateToInt(record.getDate())); adjHrsPksLoomds.setInt(4, record.getLoomNumber()); adjHrsPksLoomds.setInt(5, record.getShift()); adjHrsPksLoomds.setInt(6, record.getWeaverNumber()); adjHrsPksLoomds.setObject(7, " " + record.getLdStyle()); adjHrsPksLoomds.setInt(8, 0); LOGGER.info(adjHrsPksLoomds.executeUpdate() + " row updated in LOOMDS"); } else { adjHrsPksLoomds2.setObject(1, record.getHours()); adjHrsPksLoomds2.setObject(2, record.getPicks()); adjHrsPksLoomds2.setInt(3, dateToInt(record.getDate())); adjHrsPksLoomds2.setInt(4, record.getLoomNumber()); adjHrsPksLoomds2.setInt(5, record.getShift()); adjHrsPksLoomds2.setInt(6, record.getWeaverNumber()); adjHrsPksLoomds2.setObject(7, " " + record.getLdStyle()); adjHrsPksLoomds2.setInt(8, 0); LOGGER.info(adjHrsPksLoomds2.executeUpdate() + " row updated in LOOMDS2"); } } /** * Change the hours (on the AS400) for the supplied record object. * The SQL statement needs a date, loom #, shift, weaver #, and style for the key to * lookup the record to be changed; these are obtained from the LoomDSRecord parameter. * * The hours will be changed to whatever record.getHours() returns. * * So basically, change the object and then call this method to save those changes to the server: * * LoomDSRecord derp; * derp.setHours(4.5); * as400.adjustHours(derp); * * @param record - A LoomDSRecord representative of the record you wish to change on the server * @throws SQLException */ public void adjustHours(LoomDSRecord record) throws SQLException{ if(record.isBonus()){ adjHoursLoomds.setObject(1, record.getHours()); adjHoursLoomds.setInt(2, dateToInt(record.getDate())); adjHoursLoomds.setInt(3, record.getLoomNumber()); adjHoursLoomds.setInt(4, record.getShift()); adjHoursLoomds.setInt(5, record.getWeaverNumber()); adjHoursLoomds.setObject(6, " " + record.getLdStyle()); adjHoursLoomds.setInt(7, 0); LOGGER.info(adjHoursLoomds.executeUpdate() + " row updated in LOOMDS"); } else { adjHoursLoomds2.setObject(1, record.getHours()); adjHoursLoomds2.setInt(2, dateToInt(record.getDate())); adjHoursLoomds2.setInt(3, record.getLoomNumber()); adjHoursLoomds2.setInt(4, record.getShift()); adjHoursLoomds2.setInt(5, record.getWeaverNumber()); adjHoursLoomds2.setObject(6, " " + record.getLdStyle()); adjHoursLoomds2.setInt(7, 0); LOGGER.info(adjHoursLoomds2.executeUpdate() + " row updated in LOOMDS2"); } } /** * Change the picks (on the AS400) for the supplied record object. * The SQL statement needs a date, loom #, shift, weaver #, and style for the key to * lookup the record to be changed; these are obtained from the LoomDSRecord parameter. * * The picks will be changed to whatever record.getPicks() returns. * * So basically, change the object and then call this method to save those changes to the server: * * LoomDSRecord derp; * derp.setPicks(154); * as400.adjustPicks(derp); * * @param record - A LoomDSRecord representative of the record you wish to change on the server * @throws SQLException */ public void adjustPicks(LoomDSRecord record) throws SQLException{ if(record.isBonus()){ adjPicksLoomds.setInt(1, record.getPicks()); adjPicksLoomds.setInt(2, dateToInt(record.getDate())); adjPicksLoomds.setInt(3, record.getLoomNumber()); adjPicksLoomds.setInt(4, record.getShift()); adjPicksLoomds.setInt(5, record.getWeaverNumber()); adjPicksLoomds.setObject(6, " " + record.getLdStyle()); adjPicksLoomds.setInt(7, 0); LOGGER.info(adjPicksLoomds.executeUpdate() + " row updated in LOOMDS"); } else { adjPicksLoomds2.setInt(1, record.getPicks()); adjPicksLoomds2.setInt(2, dateToInt(record.getDate())); adjPicksLoomds2.setInt(3, record.getLoomNumber()); adjPicksLoomds2.setInt(4, record.getShift()); adjPicksLoomds2.setInt(5, record.getWeaverNumber()); adjPicksLoomds2.setObject(6, " " + record.getLdStyle()); adjPicksLoomds2.setInt(7, 0); LOGGER.info(adjPicksLoomds2.executeUpdate() + " row updated in LOOMDS2"); } } /** * Changes the weaver number (on the AS400) for the supplied record object. * The SQL statement needs a date, loom #, shift, weaver #, and style for the key to * lookup the record to be changed; these are obtained from the LoomDSRecord parameter. * * Since the weaver number is part of the key we need to lookup the appropriate record on * the server we need an extra parameter (currentWeaver) to supply the currentWeaver number * for building the record key. * * The new weaver number is obtained from the LoomDsRecord object. * * Example: * LoomDsRecord derp; * int oldWeaver = derp.getWeaver(); * derp.setWeaver(888); * as400.changeWeaver(derp, oldWeaver); * * @param record - A LoomDSRecord representative of the record you wish to change on the server * @param currentWeaver - The weaver number currently on the server for the record you wish to change * @throws SQLException */ public void changeWeaver(LoomDSRecord record, int currentWeaver) throws SQLException{ chgWeaverLoomds.setInt(1, record.getWeaverNumber()); chgWeaverLoomds.setInt(2, dateToInt(record.getDate())); chgWeaverLoomds.setInt(3, record.getLoomNumber()); chgWeaverLoomds.setInt(4, record.getShift()); chgWeaverLoomds.setInt(5, currentWeaver); chgWeaverLoomds.setObject(6, " " + record.getLdStyle()); chgWeaverLoomds.setInt(7, 0); LOGGER.info(chgWeaverLoomds.executeUpdate() + " row updated in LOOMDS"); chgWeaverLoomds2.setInt(1, record.getWeaverNumber()); chgWeaverLoomds2.setInt(2, dateToInt(record.getDate())); chgWeaverLoomds2.setInt(3, record.getLoomNumber()); chgWeaverLoomds2.setInt(4, record.getShift()); chgWeaverLoomds2.setInt(5, currentWeaver); chgWeaverLoomds2.setObject(6, " " + record.getLdStyle()); chgWeaverLoomds2.setInt(7, 0); LOGGER.info(chgWeaverLoomds2.executeUpdate() + " row updated in LOOMDS2"); } /** * Change the down time code (on the AS400) for the supplied record object. * The SQL statement needs a date, loom #, shift, weaver #, and style for the key to * lookup the record to be changed; these are obtained from the LoomDSRecord parameter. * * The down time code will be change to whatever record.getDownTimeCode() returns. * * So basically, change the object and then call this method to save those changes to the server: * * LoomDSRecord derp; * derp.setDownTimeCode("IC"); * as400.changeDTCode(derp); * * @param record - A LoomDSRecord representative of the record you wish to change on the server * @throws SQLException */ public void changeDtCode(LoomDSRecord record) throws SQLException{ chgDtCodeLoomds.setObject(1, record.getDownTimeCode()); chgDtCodeLoomds.setInt(2, dateToInt(record.getDate())); chgDtCodeLoomds.setInt(3, record.getLoomNumber()); chgDtCodeLoomds.setInt(4, record.getShift()); chgDtCodeLoomds.setInt(5, record.getWeaverNumber()); chgDtCodeLoomds.setObject(6, " " + record.getLdStyle()); chgDtCodeLoomds.setInt(7, 0); //This field is never used on the AS400; always zero LOGGER.info(chgDtCodeLoomds.executeUpdate() + " row updated in LOOMDS"); chgDtCodeLoomds2.setObject(1, record.getDownTimeCode()); chgDtCodeLoomds2.setInt(2, dateToInt(record.getDate())); chgDtCodeLoomds2.setInt(3, record.getLoomNumber()); chgDtCodeLoomds2.setInt(4, record.getShift()); chgDtCodeLoomds2.setInt(5, record.getWeaverNumber()); chgDtCodeLoomds2.setObject(6, " " + record.getLdStyle()); chgDtCodeLoomds2.setInt(7, 0); //This field is never used on the AS400; always zero LOGGER.info(chgDtCodeLoomds2.executeUpdate() + " row updated in LOOMDS2"); } /** * Down time codes will probably never change; despite that I decided against hard-coding them in and went with this approach instead. * We are opening a connection with the database anyway so we might as well grab the DT codes quick on application start up. * * Grabs down time codes and their descriptions from the server and stores them in the downTimeCodeLookup class var for speedy lookups later. * Since downTimeCodeLookup is a static class variable, after this class is instantiated at least once you will be able to get the description * for any DT code by calling: * * String description = AS400Interface.downTimeCodeLookup.get("EW"); //Don't do this * String description = AS400Interface.dtCodeLookup("EW"); //Same result; Encapsulation FTW * * This will work from any context since it's a class variable/method. * @throws SQLException */ private final void setUpDTcodeHashMap() throws SQLException{ LOGGER.info("Caching down time codes/decriptions locally from server."); ResultSet rs = this.conn.createStatement().executeQuery("select IEDTCD, IEDTDS from stmdata.iedtfl order by IEDTCD"); while(rs.next()) { AS400Interface.downTimeCodeLookup.put(rs.getString(1).trim(), rs.getString(2).trim()); } rs.close(); } /** * Lookup a down time code description from the hash table created during init. * @param code - The code you want the description for (1 or 2 characters only) * @return A string (30 chars max) containing the description of the supplied down time code */ public static final String dtCodeLookup(String code){ return AS400Interface.downTimeCodeLookup.get(code); } /** * Cache weaver names locally for speedy lookups later. * See documentation for setUpDTcodeHashMap() for a more detailed explanation. * @throws SQLException */ private final void setUpWeaverHashMap() throws SQLException{ LOGGER.info("Caching weaver table locally from server."); ResultSet rs = this.conn.createStatement().executeQuery("select WVR#, WVRNAM from stmdata.iewvms where shift > 0 order by WVR#"); while(rs.next()) { AS400Interface.weaverNameLookup.put(rs.getInt(1), rs.getString(2).trim()); } rs.close(); } /** * Lookup a weaver name from the hash table created during init * @param weaver - The weaver number whos name you want * @return A string (15 chars max) containing the name associated with the supplied weaver number */ public static final String weaverLookup(int weaver){ return AS400Interface.weaverNameLookup.get(weaver); } /** * Cache all loom speeds locally in a hash table for speedy lookups later * See documentation for setUpDTcodeHashMap() for a more detailed explanation. * @throws SQLException */ private final void setUpLoomPPHHashMap() throws SQLException{ LOGGER.info("Caching loom speeds locally from server."); ResultSet rs = this.conn.createStatement().executeQuery("select lmlomn, (lmppm * (100.0 / 82.0)) as max_picks_per_hour from stmdata.loomms where lmlomn > 200"); while(rs.next()) { AS400Interface.loomPPHLookup.put(rs.getInt(1), rs.getFloat(2)); } rs.close(); } /** * Get a loom speed in 1000s Picks/hour from the hash table we created at init. * @param loom - The loom number whos speed you want * @return The speed in 1000s of Picks/hour */ public static final float loomSpeedLookup(int loom){ return AS400Interface.loomPPHLookup.get(loom); } /** * Returns all down time codes and their descriptions in a string array. * This is used for creating a JComboBox in the GUI. * @return */ public static final String[] getDtCodeChoices(){ String[] ret = new String[downTimeCodeLookup.size() + 1]; //+1 since we want to include "None" as a choice ret[0] = ""; int i = 1; for (Map.Entry entry : downTimeCodeLookup.entrySet()) { ret[i] = entry.getKey() + " - " + entry.getValue(); i++; } Arrays.sort(ret); //Sort the array; ret[0] is blank at this point and will be placed at the beginning of the array ret[0] = "None"; //Now stick "None" into ret[0] so it will be at the top of the JComboBox return ret; } /** * Converts a java.util.Date into a integer date in yyMMdd format. * * Example: June 30th, 2013 --> 130630 * * In many files on the AS400 dates are stored in this format, so this is desirable when writing information * back to the database. * * @param d a java.util.Date to convert * @return */ public static final int dateToInt(Date d){ return Integer.parseInt(new SimpleDateFormat("yyMMdd").format(d)); } /** * Many dates are stored in yyMMdd format as a single integer on the AS400; this method can parse that * into a java.util.Date object which is handy when working with dates read from the server. * * Example: 140120 --> January 20th, 2014 * 990315 --> March 15th, 2099 * * @param d an integer date (yyMMdd) to convert to a java.util.Date * @return */ public static final Date intToDate(int d){ Calendar ret = Calendar.getInstance(); ret.set(((d / 10000) + 2000), (((d - ((d / 10000) * 10000)) / 100) - 1), (d % 100), 0, 0); //Hows this for a one-liner haha... return ret.getTime(); } }